diff --git a/src/chartgenerator.php b/src/chartgenerator.php index 58f4165..d610478 100644 --- a/src/chartgenerator.php +++ b/src/chartgenerator.php @@ -153,7 +153,6 @@ if ( !$content['error_occured'] ) $stream = $stream_config->LogStreamFactory($stream_config); $stream->SetFilter($content['chart_defaultfilter']); - // Set Columns we want to open! $content['ChartColumns'] = array(); // First add filter fields to array @@ -261,6 +260,8 @@ if ( !$content['error_occured'] ) // Create $p1 = new PiePlot3D($YchartData); + $graph->Add($p1); + $p1->SetLegends($XchartData); $p1->SetEdge('#333333', 1); $p1->SetTheme('earth'); /* "earth" * "pastel" * "sand" * "water" */ @@ -286,11 +287,10 @@ if ( !$content['error_occured'] ) // Adjust other Pie Properties $p1->SetLabelMargin(5); - $p1->SetCenter(0.4,0.65); + $p1->SetCenter(0.5,0.45); $p1->SetSize(0.3); $p1->SetAngle(60); - $graph->Add($p1); } else if ( $content['chart_type'] == CHART_BARS_VERTICAL ) { @@ -304,6 +304,7 @@ if ( !$content['error_occured'] ) $graph->SetScale("textlin"); $graph->SetMarginColor('white'); $graph->SetBox(); // Box around plotarea + $graph->img->SetAlphaBlending(true); // Setup X-AXIS // $graph->xaxis->SetFont(FF_VERA,FS_NORMAL,10); @@ -318,11 +319,8 @@ if ( !$content['error_occured'] ) else $graph->xaxis->SetLabelAngle(0); -// $graph->xaxis->scale->SetGrace(30); // So the value is readable - // Setup Y-AXIS $graph->yaxis->scale->SetGrace(10); // So the value is readable -// $graph->yaxis->SetLabelFormat('%d %%'); // Show 0 label on Y-axis (default is not to show) $graph->yscale->ticks->SupressZeroLabel(false); @@ -339,8 +337,6 @@ if ( !$content['error_occured'] ) // Set Graph footer $graph->footer->left->Set ("LogAnalyzer v" . $content['BUILDNUMBER'] . "\n" . GetAndReplaceLangStr($content['LN_STATS_GENERATEDAT'], date("Y-m-d")) ); $graph->footer->left->SetFont( FF_VERA, FS_NORMAL, 7); -// $graph->footer->right->Set ( GetAndReplaceLangStr($content['LN_STATS_GENERATEDAT'], date("Y-m-d")) ); -// $graph->footer->right->SetFont( FF_VERA, FS_NORMAL, 8); // Setup the X and Y grid $graph->ygrid->SetFill(true,'#DDDDDD@0.5','#BBBBBB@0.5'); @@ -352,34 +348,35 @@ if ( !$content['error_occured'] ) // Create and Add bar pot $bplot = new BarPlot($YchartData); + $graph->Add($bplot); + + // Fill properties of barpot $bplot->SetWidth(0.6); $fcol='#440000'; $tcol='#FF9090'; $bplot->SetFillGradient($fcol,$tcol,GRAD_LEFT_REFLECTION); - $graph->Add($bplot); // Display value in bars $bplot->value->Show(); $bplot->value->SetFont(FF_VERA,FS_NORMAL,8); -// $bplot->value->SetAlign('left','center'); -// $bplot->value->SetColor("black","darkred"); $bplot->value->SetFormat('%d'); // Add links $bplot->SetCSIMTargets($chartImageMapLinks, $chartImageMapAlts, $chartImageMapTargets); - // TODO: Make Optional! // Create and Add filled line plot $lplot = new LinePlot($YchartData); - $lplot->SetFillColor('skyblue@0.7'); - $lplot->SetColor('navy@0.7'); + $graph->Add($lplot); + // Fill properties of line plot $lplot->SetBarCenter(); $lplot->mark->SetType(MARK_SQUARE); + $lplot->mark->SetSize(6); + $lplot->SetFillColor('#7395b0@0.5'); + $lplot->SetColor('#7395b0@0.5'); $lplot->mark->SetColor('blue@0.7'); $lplot->mark->SetFillColor('lightblue'); - $lplot->mark->SetSize(6); - $graph->Add($lplot); + } else if ( $content['chart_type'] == CHART_BARS_HORIZONTAL ) { @@ -409,8 +406,6 @@ if ( !$content['error_occured'] ) $graph->yaxis->SetLabelFormat('%d'); $graph->yaxis->SetLabelSide(SIDE_RIGHT); $graph->yaxis->SetTickSide(SIDE_LEFT); -// $graph->yaxis->SetTitleSide(SIDE_RIGHT); -// $graph->yaxis->SetTitleMargin(35); $graph->yaxis->SetPos('max'); $graph->yaxis->SetTextLabelInterval(2); @@ -430,8 +425,6 @@ if ( !$content['error_occured'] ) // Set Graph footer $graph->footer->left->Set ("LogAnalyzer v" . $content['BUILDNUMBER'] . "\n" . GetAndReplaceLangStr($content['LN_STATS_GENERATEDAT'], date("Y-m-d")) ); $graph->footer->left->SetFont( FF_VERA, FS_NORMAL, 7); -// $graph->footer->right->Set ( GetAndReplaceLangStr($content['LN_STATS_GENERATEDAT'], date("Y-m-d")) ); -// $graph->footer->right->SetFont( FF_VERA, FS_NORMAL, 8); // Setup the X and Y grid $graph->ygrid->SetFill(true,'#DDDDDD@0.5','#BBBBBB@0.5'); @@ -443,17 +436,17 @@ if ( !$content['error_occured'] ) // Create and Add bar pot $bplot = new BarPlot($YchartData); + $graph->Add($bplot); + + // Fill properties of barpot $bplot->SetWidth(0.6); $fcol='#440000'; $tcol='#FF9090'; $bplot->SetFillGradient($fcol,$tcol,GRAD_LEFT_REFLECTION); - $graph->Add($bplot); // Display value in bars $bplot->value->Show(); $bplot->value->SetFont(FF_VERA,FS_NORMAL, 8); -// $bplot->value->SetAlign('left','center'); -// $bplot->value->SetColor("black","darkred"); $bplot->value->SetFormat('%d'); // Add links @@ -462,14 +455,15 @@ if ( !$content['error_occured'] ) // TODO: Make Optional! // Create and Add filled line plot $lplot = new LinePlot($YchartData); - $lplot->SetFillColor('skyblue@0.7'); - $lplot->SetColor('navy@0.7'); + $graph->Add($lplot); + // Fill properties of line plot $lplot->SetBarCenter(); $lplot->mark->SetType(MARK_SQUARE); + $lplot->mark->SetSize(6); + $lplot->SetFillColor('#7395b0@0.5'); + $lplot->SetColor('#7395b0@0.5'); $lplot->mark->SetColor('blue@0.7'); $lplot->mark->SetFillColor('lightblue'); - $lplot->mark->SetSize(6); - $graph->Add($lplot); } else { diff --git a/src/classes/class_template.php b/src/classes/class_template.php index 5cc676c..f69ed17 100644 --- a/src/classes/class_template.php +++ b/src/classes/class_template.php @@ -59,14 +59,13 @@ class Template { var $extension = ''; var $template, $vars, $page; - public function Template ($fname = '') { - self::__construct($fname); - } - - public function __construct ($fname = '') { + function __construct ($fname = '') { if ($fname) $this->filename = $fname; } + function Template ($fname = '') { + self::__construct($fname); + } function set_path ($path) { $this->path = $path; diff --git a/src/classes/jpgraph/README b/src/classes/jpgraph/README new file mode 100644 index 0000000..9b58dbd --- /dev/null +++ b/src/classes/jpgraph/README @@ -0,0 +1,66 @@ +README FOR JPGRAPH 4.0.1 +========================= + +This package contains the JpGraph PHP library version 4.0.1 + +The library is Copyright (C) 2000-2010 Asial Corporatoin and +released under dual license QPL 1.0 for open source and educational +use and JpGraph Professional License for commercial use. + +Please see full license details at +http://jpgraph.net/pro/ +http://jpgraph.net/download/ + +* -------------------------------------------------------------------- +* PHP4 IS NOT SUPPORTED IN 3.x or 4.x SERIES +* -------------------------------------------------------------------- + +Requirements: +------------- +Miminum: +* PHP 5.1.0 or higher +* GD 2.0.28 or higher +Note: Earlier versions might work but is unsupported. + +Recommended: +* >= PHP 5.2.0 +* PHP Builtin GD library + +Installation +------------ +1. Make sure that the PHP version is compatible with the stated + requirements and that the PHP installation has support for + the GD library. Please run phpinfo() to check if GD library + is supported in the installation. + If the GD library doesn't seem to be installed + please consult the PHP manual under section "Image" for + instructions on where to find this library. Please refer to + the manual section "Verifying your PHP installation" + +2. Unzip and copy the files to a directory of your choice where Your + httpd sever can access them. + For a global site installation you should copy the files to + somewhere in the PHP search path. + +3. Check that the default directory paths in jpg-config.inc.php + for cache directory and TTF directory suits your installation. + Note1: The default directories are different depending on if + the library is running on Windows or UNIX. + Note2: Apache/PHP must have write permission to your cache + directory if you enable the cache feature. By default the cache + is disabled. + + +Documentation +------------- +The installation includes HTML documentation and reference guide for the +library. The portal page for all documentation is +/docs/index.html + + +Bug reports and suggestions +--------------------------- +Should be reported using the contact form at + +http://jpgraph.net/contact/ + diff --git a/src/classes/jpgraph/fonts/DejaVuSans-Bold.ttf b/src/classes/jpgraph/fonts/DejaVuSans-Bold.ttf new file mode 100644 index 0000000..ac313d2 Binary files /dev/null and b/src/classes/jpgraph/fonts/DejaVuSans-Bold.ttf differ diff --git a/src/classes/jpgraph/fonts/DejaVuSans-BoldOblique.ttf b/src/classes/jpgraph/fonts/DejaVuSans-BoldOblique.ttf new file mode 100644 index 0000000..c818ae6 Binary files /dev/null and b/src/classes/jpgraph/fonts/DejaVuSans-BoldOblique.ttf differ diff --git a/src/classes/jpgraph/fonts/DejaVuSans-Oblique.ttf b/src/classes/jpgraph/fonts/DejaVuSans-Oblique.ttf new file mode 100644 index 0000000..d5ac60d Binary files /dev/null and b/src/classes/jpgraph/fonts/DejaVuSans-Oblique.ttf differ diff --git a/src/classes/jpgraph/fonts/DejaVuSans.ttf b/src/classes/jpgraph/fonts/DejaVuSans.ttf new file mode 100644 index 0000000..a99969e Binary files /dev/null and b/src/classes/jpgraph/fonts/DejaVuSans.ttf differ diff --git a/src/classes/jpgraph/fonts/FF_FONT0-Bold.gdf b/src/classes/jpgraph/fonts/FF_FONT0-Bold.gdf new file mode 100644 index 0000000..3b371f8 Binary files /dev/null and b/src/classes/jpgraph/fonts/FF_FONT0-Bold.gdf differ diff --git a/src/classes/jpgraph/fonts/FF_FONT0.gdf b/src/classes/jpgraph/fonts/FF_FONT0.gdf new file mode 100644 index 0000000..e231b71 Binary files /dev/null and b/src/classes/jpgraph/fonts/FF_FONT0.gdf differ diff --git a/src/classes/jpgraph/fonts/FF_FONT1-Bold.gdf b/src/classes/jpgraph/fonts/FF_FONT1-Bold.gdf new file mode 100644 index 0000000..d62f0b3 Binary files /dev/null and b/src/classes/jpgraph/fonts/FF_FONT1-Bold.gdf differ diff --git a/src/classes/jpgraph/fonts/FF_FONT1.gdf b/src/classes/jpgraph/fonts/FF_FONT1.gdf new file mode 100644 index 0000000..7b5b0f6 Binary files /dev/null and b/src/classes/jpgraph/fonts/FF_FONT1.gdf differ diff --git a/src/classes/jpgraph/fonts/FF_FONT2-Bold.gdf b/src/classes/jpgraph/fonts/FF_FONT2-Bold.gdf new file mode 100644 index 0000000..6e40284 Binary files /dev/null and b/src/classes/jpgraph/fonts/FF_FONT2-Bold.gdf differ diff --git a/src/classes/jpgraph/fonts/FF_FONT2.gdf b/src/classes/jpgraph/fonts/FF_FONT2.gdf new file mode 100644 index 0000000..50bca09 Binary files /dev/null and b/src/classes/jpgraph/fonts/FF_FONT2.gdf differ diff --git a/src/classes/jpgraph/gd_image.inc.php b/src/classes/jpgraph/gd_image.inc.php index c2ec49e..d13ce28 100644 --- a/src/classes/jpgraph/gd_image.inc.php +++ b/src/classes/jpgraph/gd_image.inc.php @@ -5,11 +5,12 @@ // Created: 2001-01-08, refactored 2008-03-29 // Ver: $Id: gd_image.inc.php 1922 2010-01-11 11:42:50Z ljp $ // -// Copyright (c) Aditus Consulting. All rights reserved. +// Copyright (c) Asial Corporation. All rights reserved. //======================================================================== require_once 'jpgraph_rgb.inc.php'; require_once 'jpgraph_ttf.inc.php'; +require_once 'imageSmoothArc.php'; // Line styles define('LINESTYLE_SOLID',1); @@ -33,19 +34,25 @@ if( !DEFINED("DEFAULT_GFORMAT") ) { // rotation. //========================================================================= class Image { - public $left_margin=30,$right_margin=30,$top_margin=20,$bottom_margin=30; public $img=null; - public $plotwidth=0,$plotheight=0; - public $width=0, $height=0; public $rgb=null; - public $current_color,$current_color_name; - public $line_weight=1, $line_style=LINESTYLE_SOLID; public $img_format; public $ttf=null; + public $line_style=LINESTYLE_SOLID; + public $current_color,$current_color_name; + public $original_width=0, $original_height=0; + public $plotwidth=0,$plotheight=0; + + // for __get, __set + private $_left_margin=30,$_right_margin=30,$_top_margin=20,$_bottom_margin=30; + //private $_plotwidth=0,$_plotheight=0; + private $_width=0, $_height=0; + private $_line_weight=1; + protected $expired=true; protected $lastx=0, $lasty=0; protected $obs_list=array(); - protected $font_size=12,$font_family=FF_FONT1, $font_style=FS_NORMAL; + protected $font_size=12,$font_family=FF_DEFAULT, $font_style=FS_NORMAL; protected $font_file=''; protected $text_halign="left",$text_valign="bottom"; protected $use_anti_aliasing=false; @@ -55,11 +62,21 @@ class Image { protected $langconv = null ; protected $iInterlace=false; protected $bbox_cache = array(); // STore the last found tetx bounding box + protected $ff_font0; + protected $ff_font0_bold; + protected $ff_font1; + protected $ff_font1_bold; + protected $ff_font2; + protected $ff_font2_bold; + //--------------- // CONSTRUCTOR function __construct($aWidth=0,$aHeight=0,$aFormat=DEFAULT_GFORMAT,$aSetAutoMargin=true) { - $this->CreateImgCanvas($aWidth,$aHeight); + + $this->original_width = $aWidth; + $this->original_height = $aHeight; + $this->CreateImgCanvas($aWidth, $aHeight); if( $aSetAutoMargin ) { $this->SetAutoMargin(); @@ -70,6 +87,12 @@ class Image { } $this->ttf = new TTF(); $this->langconv = new LanguageConv(); + + $this->ff_font0 = imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT0.gdf"); + $this->ff_font1 = imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT1.gdf"); + $this->ff_font2 = imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT2.gdf"); + $this->ff_font1_bold = imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT1-Bold.gdf"); + $this->ff_font2_bold = imageloadfont(dirname(__FILE__) . "/fonts/FF_FONT2-Bold.gdf"); } // Enable interlacing in images @@ -93,6 +116,10 @@ class Image { } function CreateRawCanvas($aWidth=0,$aHeight=0) { + + $aWidth *= SUPERSAMPLING_SCALE; + $aHeight *= SUPERSAMPLING_SCALE; + if( $aWidth <= 1 || $aHeight <= 1 ) { JpGraphError::RaiseL(25082,$aWidth,$aHeight);//("Illegal sizes specified for width or height when creating an image, (width=$aWidth, height=$aHeight)"); } @@ -146,7 +173,7 @@ class Image { // Set canvas color (will also be the background color for a // a pallett image $this->SetColor($this->canvascolor); - $this->FilledRectangle(0,0,$aWidth-1,$aHeight-1); + $this->FilledRectangle(0,0,$this->width-1,$this->height-1); return $old ; } @@ -243,7 +270,7 @@ class Image { function SetFont($family,$style=FS_NORMAL,$size=10) { $this->font_family=$family; $this->font_style=$style; - $this->font_size=$size; + $this->font_size=$size*SUPERSAMPLING_SCALE; $this->font_file=''; if( ($this->font_family==FF_FONT1 || $this->font_family==FF_FONT2) && $this->font_style==FS_BOLD ){ ++$this->font_family; @@ -252,9 +279,12 @@ class Image { // Check that this PHP has support for TTF fonts if( !function_exists('imagettfbbox') ) { - JpGraphError::RaiseL(25087);//('This PHP build has not been configured with TTF support. You need to recompile your PHP installation with FreeType support.'); + // use internal font when php is configured without '--with-ttf' + $this->font_family = FF_FONT1; +// JpGraphError::RaiseL(25087);//('This PHP build has not been configured with TTF support. You need to recompile your PHP installation with FreeType support.'); + } else { + $this->font_file = $this->ttf->File($this->font_family,$this->font_style); } - $this->font_file = $this->ttf->File($this->font_family,$this->font_style); } } @@ -620,8 +650,10 @@ class Image { $y += $dir==0 ? $h/2 : $w/2; } + $use_font = $this->font_family; + if( $dir==90 ) { - imagestringup($this->img,$this->font_family,$x,$y,$txt,$this->current_color); + imagestringup($this->img,$use_font,$x,$y,$txt,$this->current_color); $aBoundingBox = array(round($x),round($y),round($x),round($y-$w),round($x+$h),round($y-$w),round($x+$h),round($y)); if( $aDebug ) { // Draw bounding box @@ -636,19 +668,19 @@ class Image { for($i=0; $i < count($tmp); ++$i) { $w1 = $this->GetTextWidth($tmp[$i]); if( $paragraph_align=="left" ) { - imagestring($this->img,$this->font_family,$x,$y-$h+1+$i*$fh,$tmp[$i],$this->current_color); + imagestring($this->img,$use_font,$x,$y-$h+1+$i*$fh,$tmp[$i],$this->current_color); } elseif( $paragraph_align=="right" ) { - imagestring($this->img,$this->font_family,$x+($w-$w1),$y-$h+1+$i*$fh,$tmp[$i],$this->current_color); + imagestring($this->img,$use_font,$x+($w-$w1),$y-$h+1+$i*$fh,$tmp[$i],$this->current_color); } else { - imagestring($this->img,$this->font_family,$x+$w/2-$w1/2,$y-$h+1+$i*$fh,$tmp[$i],$this->current_color); + imagestring($this->img,$use_font,$x+$w/2-$w1/2,$y-$h+1+$i*$fh,$tmp[$i],$this->current_color); } } } else { //Put the text - imagestring($this->img,$this->font_family,$x,$y-$h+1,$txt,$this->current_color); + imagestring($this->img,$use_font,$x,$y-$h+1,$txt,$this->current_color); } if( $aDebug ) { // Draw the bounding rectangle and the bounding box @@ -1075,12 +1107,15 @@ class Image { } function SetMargin($lm,$rm,$tm,$bm) { + $this->left_margin=$lm; $this->right_margin=$rm; $this->top_margin=$tm; $this->bottom_margin=$bm; - $this->plotwidth=$this->width - $this->left_margin-$this->right_margin ; - $this->plotheight=$this->height - $this->top_margin-$this->bottom_margin ; + + $this->plotwidth = $this->width - $this->left_margin - $this->right_margin; + $this->plotheight = $this->height - $this->top_margin - $this->bottom_margin; + if( $this->width > 0 && $this->height > 0 ) { if( $this->plotwidth < 0 || $this->plotheight < 0 ) { JpGraphError::RaiseL(25130, $this->plotwidth, $this->plotheight); @@ -1126,7 +1161,7 @@ class Image { function SetLineWeight($weight) { - $old = $this->line_weight; + $old = $this->line_weight; imagesetthickness($this->img,$weight); $this->line_weight = $weight; return $old; @@ -1153,6 +1188,7 @@ class Image { $style=IMG_ARC_PIE; if( abs($s-$e) > 0 ) { imagefilledarc($this->img,round($xc),round($yc),round($w),round($h),$s,$e,$this->current_color,$style); +// $this->DrawImageSmoothArc($this->img,round($xc),round($yc),round($w),round($h),$s,$e,$this->current_color,$style); } } @@ -1200,10 +1236,13 @@ class Image { function Circle($xc,$yc,$r) { imageellipse($this->img,round($xc),round($yc),$r*2,$r*2,$this->current_color); +// $this->DrawImageSmoothArc($this->img,round($xc),round($yc),$r*2+1,$r*2+1,0,360,$this->current_color); +// $this->imageSmoothCircle($this->img, round($xc),round($yc), $r*2+1, $this->current_color); } function FilledCircle($xc,$yc,$r) { imagefilledellipse($this->img,round($xc),round($yc),2*$r,2*$r,$this->current_color); +// $this->DrawImageSmoothArc($this->img, round($xc), round($yc), 2*$r, 2*$r, 0, 360, $this->current_color); } // Linear Color InterPolation @@ -1240,13 +1279,18 @@ class Image { } // Same as Line but take the line_style into account - function StyleLine($x1,$y1,$x2,$y2,$aStyle='') { + function StyleLine($x1,$y1,$x2,$y2,$aStyle='', $from_grid_class = false) { if( $this->line_weight <= 0 ) return; if( $aStyle === '' ) { $aStyle = $this->line_style; } + $dashed_line_method = 'DashedLine'; + if ($from_grid_class) { + $dashed_line_method = 'DashedLineForGrid'; + } + // Add error check since dashed line will only work if anti-alias is disabled // this is a limitation in GD @@ -1265,13 +1309,13 @@ class Image { switch( $aStyle ) { case 2: // Dotted - $this->DashedLine($x1,$y1,$x2,$y2,2,6); + $this->$dashed_line_method($x1,$y1,$x2,$y2,2,6); break; case 3: // Dashed - $this->DashedLine($x1,$y1,$x2,$y2,5,9); + $this->$dashed_line_method($x1,$y1,$x2,$y2,5,9); break; case 4: // Longdashes - $this->DashedLine($x1,$y1,$x2,$y2,9,13); + $this->$dashed_line_method($x1,$y1,$x2,$y2,9,13); break; default: JpGraphError::RaiseL(25104,$this->line_style);//(" Unknown line style: $this->line_style "); @@ -1291,19 +1335,55 @@ class Image { // Dashed line does not work with anti-alias enabled. This // is a limitation in GD. if( $this->use_anti_aliasing ) { - JpGraphError::RaiseL(25129); // Anti-alias can not be used with dashed lines. Please disable anti-alias or use solid lines. +// JpGraphError::RaiseL(25129); // Anti-alias can not be used with dashed lines. Please disable anti-alias or use solid lines. } - - + $x1 = round($x1); $x2 = round($x2); $y1 = round($y1); $y2 = round($y2); + $dash_length *= SUPERSAMPLING_SCALE; + $dash_space *= SUPERSAMPLING_SCALE; + $style = array_fill(0,$dash_length,$this->current_color); $style = array_pad($style,$dash_space,IMG_COLOR_TRANSPARENT); imagesetstyle($this->img, $style); imageline($this->img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED); + + $this->lastx = $x2; + $this->lasty = $y2; + } + + function DashedLineForGrid($x1,$y1,$x2,$y2,$dash_length=1,$dash_space=4) { + + if( $this->line_weight <= 0 ) return; + + // Add error check to make sure anti-alias is not enabled. + // Dashed line does not work with anti-alias enabled. This + // is a limitation in GD. + if( $this->use_anti_aliasing ) { +// JpGraphError::RaiseL(25129); // Anti-alias can not be used with dashed lines. Please disable anti-alias or use solid lines. + } + + $x1 = round($x1); + $x2 = round($x2); + $y1 = round($y1); + $y2 = round($y2); + + /* + $dash_length *= $this->scale; + $dash_space *= $this->scale; + */ + + $dash_length = 2; + $dash_length = 4; + imagesetthickness($this->img, 1); + $style = array_fill(0,$dash_length, $this->current_color); //hexdec('CCCCCC')); + $style = array_pad($style,$dash_space,IMG_COLOR_TRANSPARENT); + imagesetstyle($this->img, $style); + imageline($this->img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED); + $this->lastx = $x2; $this->lasty = $y2; } @@ -1318,6 +1398,7 @@ class Image { $y2 = round($y2); imageline($this->img,$x1,$y1,$x2,$y2,$this->current_color); +// $this->DrawLine($this->img, $x1, $y1, $x2, $y2, $this->line_weight, $this->current_color); $this->lastx=$x2; $this->lasty=$y2; } @@ -1579,13 +1660,24 @@ class Image { } // Stream image to browser or to file - function Stream($aFile="") { + function Stream($aFile=NULL) { + $this->DoSupersampling(); + $func="image".$this->img_format; if( $this->img_format=="jpeg" && $this->quality != null ) { $res = @$func($this->img,$aFile,$this->quality); - } + + if(!$res){ + if($aFile != NULL){ + JpGraphError::RaiseL(25107,$aFile);//("Can't write to file '$aFile'. Check that the process running PHP has enough permission."); + }else{ + JpGraphError::RaiseL(25108);//("Can't stream image. This is most likely due to a faulty PHP/GD setup. Try to recompile PHP and use the built-in GD library that comes with PHP."); + } + + } + } else { - if( $aFile != "" ) { + if( $aFile != NULL ) { $res = @$func($this->img,$aFile); if( !$res ) { JpGraphError::RaiseL(25107,$aFile);//("Can't write to file '$aFile'. Check that the process running PHP has enough permission."); @@ -1601,6 +1693,18 @@ class Image { } } + // Do SuperSampling using $scale + function DoSupersampling() { + if (SUPERSAMPLING_SCALE <= 1) { + return $this->img; + } + + $dst_img = @imagecreatetruecolor($this->original_width, $this->original_height); + imagecopyresampled($dst_img, $this->img, 0, 0, 0, 0, $this->original_width, $this->original_height, $this->width, $this->height); + $this->Destroy(); + return $this->img = $dst_img; + } + // Clear resources used by image (this is normally not used since all resources are/should be // returned when the script terminates function Destroy() { @@ -1645,6 +1749,194 @@ class Image { } } } + + /** + * Draw Line + */ + function DrawLine($im, $x1, $y1, $x2, $y2, $weight, $color) { + if ($weight == 1) { + return imageline($im,$x1,$y1,$x2,$y2,$color); + } + + $angle=(atan2(($y1 - $y2), ($x2 - $x1))); + + $dist_x = $weight * (sin($angle)) / 2; + $dist_y = $weight * (cos($angle)) / 2; + + $p1x=ceil(($x1 + $dist_x)); + $p1y=ceil(($y1 + $dist_y)); + $p2x=ceil(($x2 + $dist_x)); + $p2y=ceil(($y2 + $dist_y)); + $p3x=ceil(($x2 - $dist_x)); + $p3y=ceil(($y2 - $dist_y)); + $p4x=ceil(($x1 - $dist_x)); + $p4y=ceil(($y1 - $dist_y)); + + $array=array($p1x,$p1y,$p2x,$p2y,$p3x,$p3y,$p4x,$p4y); + imagefilledpolygon ( $im, $array, (count($array)/2), $color ); + + // for antialias + imageline($im, $p1x, $p1y, $p2x, $p2y, $color); + imageline($im, $p3x, $p3y, $p4x, $p4y, $color); + return; + + + + return imageline($this->img,$x1,$y1,$x2,$y2,$this->current_color); + $weight = 8; + if ($weight <= 1) { + return imageline($this->img,$x1,$y1,$x2,$y2,$this->current_color); + } + + $pts = array(); + + $weight /= 2; + + if ($y2 - $y1 == 0) { + // x line + $pts = array(); + $pts[] = $x1; $pts[] = $y1 - $weight; + $pts[] = $x1; $pts[] = $y1 + $weight; + $pts[] = $x2; $pts[] = $y2 + $weight; + $pts[] = $x2; $pts[] = $y2 - $weight; + + } elseif ($x2 - $x1 == 0) { + // y line + $pts = array(); + $pts[] = $x1 - $weight; $pts[] = $y1; + $pts[] = $x1 + $weight; $pts[] = $y1; + $pts[] = $x2 + $weight; $pts[] = $y2; + $pts[] = $x2 - $weight; $pts[] = $y2; + + } else { + + var_dump($x1, $x2, $y1, $y2); + $length = sqrt(pow($x2 - $x1, 2) + pow($y2 - $y1, 2)); + var_dump($length);exit; + exit; + +/* + $lean = ($y2 - $y1) / ($x2 - $x1); + $lean2 = -1 / $lean; + $sin = $lean / ($y2 - $y1); + $cos = $lean / ($x2 - $x1); + + $pts[] = $x1 + (-$weight * $sin); $pts[] = $y1 + (-$weight * $cos); + $pts[] = $x1 + (+$weight * $sin); $pts[] = $y1 + (+$weight * $cos); + $pts[] = $x2 + (+$weight * $sin); $pts[] = $y2 + (+$weight * $cos); + $pts[] = $x2 + (-$weight * $sin); $pts[] = $y2 + (-$weight * $cos); +*/ + } + +//print_r($pts);exit; + if (count($pts)/2 < 3) { + return; + } + + imagesetthickness($im, 1); + imagefilledpolygon($im, $pts,count($pts)/2, $color); + + + $weight *= 2; + +// $this->DrawImageSmoothArc($im, $x1, $y1, $weight, $weight, 0, 360, $color); +// $this->DrawImageSmoothArc($im, $x2, $y2, $weight, $weight, 0, 360, $color); + } + + + function DrawImageSmoothArc($im, $xc, $yc, $w, $h, $s, $e, $color, $style = null) { + $tmp = $s; + $s = (360 - $e) / 180 * M_PI; + $e = (360 - $tmp) / 180 * M_PI; + return imageSmoothArc($im, round($xc), round($yc), round($w), round($h), $this->CreateColorForImageSmoothArc($color), $s, $e); + } + + function CreateColorForImageSmoothArc($color) { + $alpha = $color >> 24 & 0xFF; + $red = $color >> 16 & 0xFF; + $green = $color >> 8 & 0xFF; + $blue = $color & 0xFF; + +//var_dump($alpha, $red, $green, $blue);exit; + + return array($red, $green, $blue, $alpha); + } + + function imageSmoothCircle( &$img, $cx, $cy, $cr, $color ) { + $ir = $cr; + $ix = 0; + $iy = $ir; + $ig = 2 * $ir - 3; + $idgr = -6; + $idgd = 4 * $ir - 10; + $fill = imageColorExactAlpha( $img, $color[ 'R' ], $color[ 'G' ], $color[ 'B' ], 0 ); + imageLine( $img, $cx + $cr - 1, $cy, $cx, $cy, $fill ); + imageLine( $img, $cx - $cr + 1, $cy, $cx - 1, $cy, $fill ); + imageLine( $img, $cx, $cy + $cr - 1, $cx, $cy + 1, $fill ); + imageLine( $img, $cx, $cy - $cr + 1, $cx, $cy - 1, $fill ); + $draw = imageColorExactAlpha( $img, $color[ 'R' ], $color[ 'G' ], $color[ 'B' ], 42 ); + imageSetPixel( $img, $cx + $cr, $cy, $draw ); + imageSetPixel( $img, $cx - $cr, $cy, $draw ); + imageSetPixel( $img, $cx, $cy + $cr, $draw ); + imageSetPixel( $img, $cx, $cy - $cr, $draw ); + while ( $ix <= $iy - 2 ) { + if ( $ig < 0 ) { + $ig += $idgd; + $idgd -= 8; + $iy--; + } else { + $ig += $idgr; + $idgd -= 4; + } + $idgr -= 4; + $ix++; + imageLine( $img, $cx + $ix, $cy + $iy - 1, $cx + $ix, $cy + $ix, $fill ); + imageLine( $img, $cx + $ix, $cy - $iy + 1, $cx + $ix, $cy - $ix, $fill ); + imageLine( $img, $cx - $ix, $cy + $iy - 1, $cx - $ix, $cy + $ix, $fill ); + imageLine( $img, $cx - $ix, $cy - $iy + 1, $cx - $ix, $cy - $ix, $fill ); + imageLine( $img, $cx + $iy - 1, $cy + $ix, $cx + $ix, $cy + $ix, $fill ); + imageLine( $img, $cx + $iy - 1, $cy - $ix, $cx + $ix, $cy - $ix, $fill ); + imageLine( $img, $cx - $iy + 1, $cy + $ix, $cx - $ix, $cy + $ix, $fill ); + imageLine( $img, $cx - $iy + 1, $cy - $ix, $cx - $ix, $cy - $ix, $fill ); + $filled = 0; + for ( $xx = $ix - 0.45; $xx < $ix + 0.5; $xx += 0.2 ) { + for ( $yy = $iy - 0.45; $yy < $iy + 0.5; $yy += 0.2 ) { + if ( sqrt( pow( $xx, 2 ) + pow( $yy, 2 ) ) < $cr ) $filled += 4; + } + } + $draw = imageColorExactAlpha( $img, $color[ 'R' ], $color[ 'G' ], $color[ 'B' ], ( 100 - $filled ) ); + imageSetPixel( $img, $cx + $ix, $cy + $iy, $draw ); + imageSetPixel( $img, $cx + $ix, $cy - $iy, $draw ); + imageSetPixel( $img, $cx - $ix, $cy + $iy, $draw ); + imageSetPixel( $img, $cx - $ix, $cy - $iy, $draw ); + imageSetPixel( $img, $cx + $iy, $cy + $ix, $draw ); + imageSetPixel( $img, $cx + $iy, $cy - $ix, $draw ); + imageSetPixel( $img, $cx - $iy, $cy + $ix, $draw ); + imageSetPixel( $img, $cx - $iy, $cy - $ix, $draw ); + } + } + + function __get($name) { + + if (strpos($name, 'raw_') !== false) { + // if $name == 'raw_left_margin' , return $this->_left_margin; + $variable_name = '_' . str_replace('raw_', '', $name); + return $this->$variable_name; + } + + $variable_name = '_' . $name; + + if (isset($this->$variable_name)) { + return $this->$variable_name * SUPERSAMPLING_SCALE; + } else { + JpGraphError::RaiseL('25132', $name); + } + } + + function __set($name, $value) { + $this->{'_'.$name} = $value; + } + } // CLASS //=================================================== diff --git a/src/classes/jpgraph/imageSmoothArc.php b/src/classes/jpgraph/imageSmoothArc.php new file mode 100644 index 0000000..a1d581f --- /dev/null +++ b/src/classes/jpgraph/imageSmoothArc.php @@ -0,0 +1,344 @@ += abs($yStart)) { + $aaStartX = true; + } else { + $aaStartX = false; + } + if ($xStop >= $yStop) { + $aaStopX = true; + } else { + $aaStopX = false; + } + //$xp = +1; $yp = -1; $xa = +1; $ya = 0; + for ( $x = 0; $x < $a; $x += 1 ) { + /*$y = $b * sqrt( 1 - ($x*$x)/($a*$a) ); + + $error = $y - (int)($y); + $y = (int)($y); + + $diffColor = imageColorExactAlpha( $img, $color[0], $color[1], $color[2], 127-(127-$color[3])*$error );*/ + + $_y1 = $dyStop*$x; + $_y2 = $dyStart*$x; + if ($xStart > $xStop) + { + $error1 = $_y1 - (int)($_y1); + $error2 = 1 - $_y2 + (int)$_y2; + $_y1 = $_y1-$error1; + $_y2 = $_y2+$error2; + } + else + { + $error1 = 1 - $_y1 + (int)$_y1; + $error2 = $_y2 - (int)($_y2); + $_y1 = $_y1+$error1; + $_y2 = $_y2-$error2; + } + /* + if ($aaStopX) + $diffColor1 = imageColorExactAlpha( $img, $color[0], $color[1], $color[2], 127-(127-$color[3])*$error1 ); + if ($aaStartX) + $diffColor2 = imageColorExactAlpha( $img, $color[0], $color[1], $color[2], 127-(127-$color[3])*$error2 ); + */ + + if ($seg == 0 || $seg == 2) + { + $i = $seg; + if (!($start > $i*M_PI/2 && $x > $xStart)) { + if ($i == 0) { + $xp = +1; $yp = -1; $xa = +1; $ya = 0; + } else { + $xp = -1; $yp = +1; $xa = 0; $ya = +1; + } + if ( $stop < ($i+1)*(M_PI/2) && $x <= $xStop ) { + $diffColor1 = imageColorExactAlpha( $img, $color[0], $color[1], $color[2], 127-(127-$color[3])*$error1 ); + $y1 = $_y1; if ($aaStopX) imageSetPixel($img, $cx+$xp*($x)+$xa, $cy+$yp*($y1+1)+$ya, $diffColor1); + + } else { + $y = $b * sqrt( 1 - ($x*$x)/($a*$a) ); + $error = $y - (int)($y); + $y = (int)($y); + $diffColor = imageColorExactAlpha( $img, $color[0], $color[1], $color[2], 127-(127-$color[3])*$error ); + $y1 = $y; if ($x < $aaAngleX ) imageSetPixel($img, $cx+$xp*$x+$xa, $cy+$yp*($y1+1)+$ya, $diffColor); + } + if ($start > $i*M_PI/2 && $x <= $xStart) { + $diffColor2 = imageColorExactAlpha( $img, $color[0], $color[1], $color[2], 127-(127-$color[3])*$error2 ); + $y2 = $_y2; if ($aaStartX) imageSetPixel($img, $cx+$xp*$x+$xa, $cy+$yp*($y2-1)+$ya, $diffColor2); + } else { + $y2 = 0; + } + if ($y2 <= $y1) imageLine($img, $cx+$xp*$x+$xa, $cy+$yp*$y1+$ya , $cx+$xp*$x+$xa, $cy+$yp*$y2+$ya, $fillColor); + } + } + + if ($seg == 1 || $seg == 3) + { + $i = $seg; + if (!($stop < ($i+1)*M_PI/2 && $x > $xStop)) { + if ($i == 1) { + $xp = -1; $yp = -1; $xa = 0; $ya = 0; + } else { + $xp = +1; $yp = +1; $xa = 1; $ya = 1; + } + if ( $start > $i*M_PI/2 && $x < $xStart ) { + $diffColor2 = imageColorExactAlpha( $img, $color[0], $color[1], $color[2], 127-(127-$color[3])*$error2 ); + $y1 = $_y2; if ($aaStartX) imageSetPixel($img, $cx+$xp*$x+$xa, $cy+$yp*($y1+1)+$ya, $diffColor2); + + } else { + $y = $b * sqrt( 1 - ($x*$x)/($a*$a) ); + $error = $y - (int)($y); + $y = (int) $y; + $diffColor = imageColorExactAlpha( $img, $color[0], $color[1], $color[2], 127-(127-$color[3])*$error ); + $y1 = $y; if ($x < $aaAngleX ) imageSetPixel($img, $cx+$xp*$x+$xa, $cy+$yp*($y1+1)+$ya, $diffColor); + } + if ($stop < ($i+1)*M_PI/2 && $x <= $xStop) { + $diffColor1 = imageColorExactAlpha( $img, $color[0], $color[1], $color[2], 127-(127-$color[3])*$error1 ); + $y2 = $_y1; if ($aaStopX) imageSetPixel($img, $cx+$xp*$x+$xa, $cy+$yp*($y2-1)+$ya, $diffColor1); + } else { + $y2 = 0; + } + if ($y2 <= $y1) imageLine($img, $cx+$xp*$x+$xa, $cy+$yp*$y1+$ya, $cx+$xp*$x+$xa, $cy+$yp*$y2+$ya, $fillColor); + } + } + } + + ///YYYYY + + for ( $y = 0; $y < $b; $y += 1 ) { + /*$x = $a * sqrt( 1 - ($y*$y)/($b*$b) ); + + $error = $x - (int)($x); + $x = (int)($x); + + $diffColor = imageColorExactAlpha( $img, $color[0], $color[1], $color[2], 127-(127-$color[3])*$error ); + */ + $_x1 = $dxStop*$y; + $_x2 = $dxStart*$y; + if ($yStart > $yStop) + { + $error1 = $_x1 - (int)($_x1); + $error2 = 1 - $_x2 + (int)$_x2; + $_x1 = $_x1-$error1; + $_x2 = $_x2+$error2; + } + else + { + $error1 = 1 - $_x1 + (int)$_x1; + $error2 = $_x2 - (int)($_x2); + $_x1 = $_x1+$error1; + $_x2 = $_x2-$error2; + } +/* + if (!$aaStopX) + $diffColor1 = imageColorExactAlpha( $img, $color[0], $color[1], $color[2], 127-(127-$color[3])*$error1 ); + if (!$aaStartX) + $diffColor2 = imageColorExactAlpha( $img, $color[0], $color[1], $color[2], 127-(127-$color[3])*$error2 ); +*/ + + if ($seg == 0 || $seg == 2) + { + $i = $seg; + if (!($start > $i*M_PI/2 && $y > $yStop)) { + if ($i == 0) { + $xp = +1; $yp = -1; $xa = 1; $ya = 0; + } else { + $xp = -1; $yp = +1; $xa = 0; $ya = 1; + } + if ( $stop < ($i+1)*(M_PI/2) && $y <= $yStop ) { + $diffColor1 = imageColorExactAlpha( $img, $color[0], $color[1], $color[2], 127-(127-$color[3])*$error1 ); + $x1 = $_x1; if (!$aaStopX) imageSetPixel($img, $cx+$xp*($x1-1)+$xa, $cy+$yp*($y)+$ya, $diffColor1); + } + if ($start > $i*M_PI/2 && $y < $yStart) { + $diffColor2 = imageColorExactAlpha( $img, $color[0], $color[1], $color[2], 127-(127-$color[3])*$error2 ); + $x2 = $_x2; if (!$aaStartX) imageSetPixel($img, $cx+$xp*($x2+1)+$xa, $cy+$yp*($y)+$ya, $diffColor2); + } else { + $x = $a * sqrt( 1 - ($y*$y)/($b*$b) ); + $error = $x - (int)($x); + $x = (int)($x); + $diffColor = imageColorExactAlpha( $img, $color[0], $color[1], $color[2], 127-(127-$color[3])*$error ); + $x1 = $x; if ($y < $aaAngleY && $y <= $yStop ) imageSetPixel($img, $cx+$xp*($x1+1)+$xa, $cy+$yp*$y+$ya, $diffColor); + } + } + } + + if ($seg == 1 || $seg == 3) + { + $i = $seg; + if (!($stop < ($i+1)*M_PI/2 && $y > $yStart)) { + if ($i == 1) { + $xp = -1; $yp = -1; $xa = 0; $ya = 0; + } else { + $xp = +1; $yp = +1; $xa = 1; $ya = 1; + } + if ( $start > $i*M_PI/2 && $y < $yStart ) { + $diffColor2 = imageColorExactAlpha( $img, $color[0], $color[1], $color[2], 127-(127-$color[3])*$error2 ); + $x1 = $_x2; if (!$aaStartX) imageSetPixel($img, $cx+$xp*($x1-1)+$xa, $cy+$yp*$y+$ya, $diffColor2); + } + if ($stop < ($i+1)*M_PI/2 && $y <= $yStop) { + $diffColor1 = imageColorExactAlpha( $img, $color[0], $color[1], $color[2], 127-(127-$color[3])*$error1 ); + $x2 = $_x1; if (!$aaStopX) imageSetPixel($img, $cx+$xp*($x2+1)+$xa, $cy+$yp*$y+$ya, $diffColor1); + } else { + $x = $a * sqrt( 1 - ($y*$y)/($b*$b) ); + $error = $x - (int)($x); + $x = (int)($x); + $diffColor = imageColorExactAlpha( $img, $color[0], $color[1], $color[2], 127-(127-$color[3])*$error ); + $x1 = $x; if ($y < $aaAngleY && $y < $yStart) imageSetPixel($img,$cx+$xp*($x1+1)+$xa, $cy+$yp*$y+$ya, $diffColor); + } + } + } + } +} + + +function imageSmoothArc ( &$img, $cx, $cy, $w, $h, $color, $start, $stop) +{ + // Originally written from scratch by Ulrich Mierendorff, 06/2006 + // Rewritten and improved, 04/2007, 07/2007 + // compared to old version: + // + Support for transparency added + // + Improved quality of edges & antialiasing + + // note: This function does not represent the fastest way to draw elliptical + // arcs. It was written without reading any papers on that subject. Better + // algorithms may be twice as fast or even more. + + // what it cannot do: It does not support outlined arcs, only filled + + // Parameters: + // $cx - Center of ellipse, X-coord + // $cy - Center of ellipse, Y-coord + // $w - Width of ellipse ($w >= 2) + // $h - Height of ellipse ($h >= 2 ) + // $color - Color of ellipse as a four component array with RGBA + // $start - Starting angle of the arc, no limited range! + // $stop - Stop angle of the arc, no limited range! + // $start _can_ be greater than $stop! + // If any value is not in the given range, results are undefined! + + // This script does not use any special algorithms, everything is completely + // written from scratch; see http://de.wikipedia.org/wiki/Ellipse for formulas. + + while ($start < 0) + $start += 2*M_PI; + while ($stop < 0) + $stop += 2*M_PI; + + while ($start > 2*M_PI) + $start -= 2*M_PI; + + while ($stop > 2*M_PI) + $stop -= 2*M_PI; + + + if ($start > $stop) + { + imageSmoothArc ( $img, $cx, $cy, $w, $h, $color, $start, 2*M_PI); + imageSmoothArc ( $img, $cx, $cy, $w, $h, $color, 0, $stop); + return; + } + + $a = 1.0*round ($w/2); + $b = 1.0*round ($h/2); + $cx = 1.0*round ($cx); + $cy = 1.0*round ($cy); + + $aaAngle = atan(($b*$b)/($a*$a)*tan(0.25*M_PI)); + $aaAngleX = $a*cos($aaAngle); + $aaAngleY = $b*sin($aaAngle); + + $a -= 0.5; // looks better... + $b -= 0.5; + + for ($i=0; $i<4;$i++) + { + if ($start < ($i+1)*M_PI/2) + { + if ($start > $i*M_PI/2) + { + if ($stop > ($i+1)*M_PI/2) + { + imageSmoothArcDrawSegment($img, $cx, $cy, $a, $b, $aaAngleX, $aaAngleY , $color, $start, ($i+1)*M_PI/2, $i); + } + else + { + imageSmoothArcDrawSegment($img, $cx, $cy, $a, $b, $aaAngleX, $aaAngleY, $color, $start, $stop, $i); + break; + } + } + else + { + if ($stop > ($i+1)*M_PI/2) + { + imageSmoothArcDrawSegment($img, $cx, $cy, $a, $b, $aaAngleX, $aaAngleY, $color, $i*M_PI/2, ($i+1)*M_PI/2, $i); + } + else + { + imageSmoothArcDrawSegment($img, $cx, $cy, $a, $b, $aaAngleX, $aaAngleY, $color, $i*M_PI/2, $stop, $i); + break; + } + } + } + } +} +?> diff --git a/src/classes/jpgraph/imgdata_balls.inc.php b/src/classes/jpgraph/imgdata_balls.inc.php new file mode 100644 index 0000000..ee5db49 --- /dev/null +++ b/src/classes/jpgraph/imgdata_balls.inc.php @@ -0,0 +1,1061 @@ + 'imgdata_large', + MARK_IMG_MBALL => 'imgdata_small', + MARK_IMG_SBALL => 'imgdata_xsmall', + MARK_IMG_BALL => 'imgdata_xsmall'); + protected $colors,$index,$maxidx; + private $colors_1 = array('blue','lightblue','brown','darkgreen', + 'green','purple','red','gray','yellow','silver','gray'); + private $index_1 = array('blue'=>9,'lightblue'=>1,'brown'=>6,'darkgreen'=>7, + 'green'=>8,'purple'=>4,'red'=>0,'gray'=>5,'silver'=>3,'yellow'=>2); + private $maxidx_1 = 9 ; + + private $colors_2 = array('blue','bluegreen','brown','cyan', + 'darkgray','greengray','gray','green', + 'greenblue','lightblue','lightred', + 'purple','red','white','yellow'); + + + private $index_2 = array('blue'=>9,'bluegreen'=>13,'brown'=>8,'cyan'=>12, + 'darkgray'=>5,'greengray'=>6,'gray'=>2,'green'=>10, + 'greenblue'=>3,'lightblue'=>1,'lightred'=>14, + 'purple'=>7,'red'=>0,'white'=>11,'yellow'=>4); + + private $maxidx_2 = 14 ; + + + private $colors_3 = array('bluegreen','cyan','darkgray','greengray', + 'gray','graypurple','green','greenblue','lightblue', + 'lightred','navy','orange','purple','red','yellow'); + + private $index_3 = array('bluegreen'=>1,'cyan'=>11,'darkgray'=>14,'greengray'=>10, + 'gray'=>3,'graypurple'=>4,'green'=>9,'greenblue'=>7, + 'lightblue'=>13,'lightred'=>0,'navy'=>2,'orange'=>12, + 'purple'=>8,'red'=>5,'yellow'=>6); + private $maxidx_3 = 14 ; + + protected $imgdata_large, $imgdata_small, $imgdata_xsmall ; + + + function GetImg($aMark,$aIdx) { + switch( $aMark ) { + case MARK_IMG_SBALL: + case MARK_IMG_BALL: + $this->colors = $this->colors_3; + $this->index = $this->index_3 ; + $this->maxidx = $this->maxidx_3 ; + break; + case MARK_IMG_MBALL: + $this->colors = $this->colors_2; + $this->index = $this->index_2 ; + $this->maxidx = $this->maxidx_2 ; + break; + default: + $this->colors = $this->colors_1; + $this->index = $this->index_1 ; + $this->maxidx = $this->maxidx_1 ; + break; + } + return parent::GetImg($aMark,$aIdx); + } + + function __construct() { + + //========================================================== + // File: bl_red.png + //========================================================== + $this->imgdata_large[0][0]= 1072 ; + $this->imgdata_large[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAByF'. + 'BMVEX/////////xsb/vb3/lIz/hIT/e3v/c3P/c2v/a2v/Y2P/'. + 'UlL/Skr/SkL/Qjn/MTH/MSn/KSn/ISH/IRj/GBj/GBD/EBD/EA'. + 'j/CAj/CAD/AAD3QkL3MTH3KSn3KSH3GBj3EBD3CAj3AAD1zMzv'. + 'QkLvISHvIRjvGBjvEBDvEAjvAADnUlLnSkrnMTnnKSnnIRjnGB'. + 'DnEBDnCAjnAADec3PeSkreISHeGBjeGBDeEAjWhITWa2vWUlLW'. + 'SkrWISnWGBjWEBDWEAjWCAjWAADOnp7Oa2vOGCHOGBjOGBDOEB'. + 'DOCAjOAADJrq7Gt7fGGBjGEBDGCAjGAADEpKS/v7+9QkK9GBC9'. + 'EBC9CAi9AAC1e3u1a2u1Skq1KSm1EBC1CAi1AACtEBCtCBCtCA'. + 'itAACngYGlCAilAACghIScOTmcCAicAACYgYGUGAiUCAiUAAiU'. + 'AACMKSmMEACMAACEa2uEGAiEAAB7GBh7CAB7AABzOTlzGBBzCA'. + 'BzAABrSkprOTlrGBhrAABjOTljAABaQkJaOTlaCABaAABSKSlS'. + 'GBhSAABKKSlKGBhKAABCGBhCCABCAAA5CAA5AAAxCAAxAAApCA'. + 'ApAAAhAAAYAACc9eRyAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'. + 'HUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkRFD'. + 'UHLytKAAAB4UlEQVR4nGNgIAK4mGjrmNq6BmFIWMmISUpKSmk5'. + 'B8ZEokj4qoiLiQCBgqald3xaBpKMj6y4sLCQkJCIvIaFV0RaUR'. + 'lCSk5cWEiAn19ASN7QwisuraihHiajKyEixM/NwckjoKrvEACU'. + 'qumpg7pAUlREiJdNmZmLT9/cMzwps7Smc3I2WEpGUkxYkJuFiY'. + 'lTxszePzY1v7Shc2oX2D+K4iLCgjzsrOw8embuYUmZeTVtPVOn'. + 'gqSslYAOF+Ln4ZHWtXMPTcjMrWno7J82rRgoZWOsqaCgrqaqqm'. + 'fn5peQmlsK1DR52vRaoFSIs5GRoYG5ub27n19CYm5pdVPnxKnT'. + 'pjWDpLydnZwcHTz8QxMSEnJLgDL9U6dNnQ6Sio4PDAgICA+PTU'. + 'zNzSkph8hADIxKS46Pj0tKTc3MLSksqWrtmQySAjuDIT8rKy0r'. + 'Kz+vtLSmur6jb9JUIJgGdjxDQUVRUVFpaUVNQ1NrZ9+kKVOmTZ'. + 'k6vR0sldJUAwQNTU2dnX0TgOJTQLrSIYFY2dPW1NbW2TNxwtQp'. + 'U6ZMmjJt2rRGWNB3TO7vnzh5MsgSoB6gy7sREdY7bRrQEDAGOb'. + 'wXOQW0TJsOEpwClmxBTTbZ7UDVIPkp7dkYaYqhuLa5trYYUxwL'. + 'AADzm6uekAAcXAAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bl_bluegreen.png + //========================================================== + $this->imgdata_large[1][0]= 1368 ; + $this->imgdata_large[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMMFi8hE9b2uAAABOVJREFUeNq9lk2sJFUVx3+3qv'. + 'tW95t57zFvhiFxmCFRUJRoNCQiJARMhiFx/Igxii5goTG6ZDAu'. + '/EhcSCIrTAgLEiKsJ8ywABNZEMJXEDYCukAmjgjzBkK/j35V1d'. + '333FtV97io97pfzwxfG86qcu/N+Z3zP+fcW/Apmfk4hx57+R/6'. + 'Rqmc9ykhsWjlsUngAA1fXIQ7b73pI/186IGHnn9dH/8frC8v4I'. + 'PiG53uaerR4GmKkv31mB8cyfjd946ZTwR66qVX9OTWIi8UKUv9'. + 'BOrZXpYZvFeiBvzI0fgSUSFKwbVG+Pl1V3HH0VvNR4KeeukV/f'. + 'PmMmdHhst76aXD64AbeVQ9bjNHaiGOC2o3wLrAb2/4LL/84ffn'. + 'fCdzkOdayKpLppBemrBsU5Y1Zdmm9LJdGU6E/t4M24Q26jRDRL'. + 'j3mdc49cSTekFsMzs5XuTsyLDUNSDQ25NwKOly9YIl22MYhJr/'. + 'uoDtBBoT0CxBRGYOAhibIaOCe//2MpfM6KHnX9cXipSlbkKWmS'. + 'nk9iv38J0jixw7vJfrTMYBOvhSoQHJBS09ANELloAGDxW8tfoW'. + 'J+5/UC8CPS0LU7r3SpYarr7M8rmFjMPLXT6/33L4si7Z2GCrQC'. + '+0ctlOaNs9DReV8vSLr85ndPLpZ/WNvHW+01kAVFBOGvJx0wYg'. + 'Sp47RIQ4Emwa8FGJXlDxSCFo5YlVgAo2hwPue/hRndboTV3EW2'. + 'Wp3k6wBp8q56QiWzecW6vwQfnPRkAWhFgILnq08jQ+R2nlUzzN'. + 'uES9Q7Vd+9fba7NmWJW61db2247qACmcjxXr45psYphsFGSLBu'. + 'kIajxqtjNwHkvAjQt0sg3crhPA2+fPz0CuyNFOghsGsr19mnFg'. + 'DGwrRm8UoAtNmQPQtRXDgdC4HImCFEKcCE0oieUWUYq2LtbiGp'. + 'mBQmppfIkjw45DK0QNNkvQ0jMBtPL0UnDRM1rN+cxKwzvOo2NP'. + 'tykR9a1kfpZNDLMG6QDYJqCTBvUe1+uxs+YKyPoGrTwY2HhvC4'. + 'CDWQd5d4xNApNQEEMgjgLdUCLBQ5cprL/trwNwKG2IUmDqDFd5'. + 'sr5BWrlxuSdLDFEFlqAzXGc4zFjupqh6uqYihpxJcEgp026l2w'. + '7wFUv7Z6AvrfRo/n0OYzPwIKE3HUKAJg2otMBiElnsF7wngis9'. + '3ZDjNnLi7huCWUZfueZKTu/M0V3HvmkOFDVxVKDG04ScejSgW5'. + 'V0q5JYFEghuDLHlTmToqDeGOCKIVtrW9hsdmXufEcNLPSXuPHa'. + 'a+bvuh9df5AH/v5PDFmbWQC3Mx+TVvfGVTRB2CodNgT2JBX003'. + 'aANZAYS/BxCv32TV/l2C03G7jgmfjGiT/qmeEmibEYm7XzAO2k'. + 'A+pbgHhBgydqu54YO5eRiLCy7yDvPP6Xqf+5Z+Lu277OYuOpiw'. + 'H15oBmlNOMcmK5RbP+PrEscGU+DSAxdg4CICIkxnLP8aNz63Og'. + 'H3/rdvOb795GVhuaYo0oBc3GGrEsUPVTwO6a7LYd+X51x3Hu/t'. + 'lP5tS65FN+6okn9U+n/sqb596dTvhOF+02myXTmkQNrOw7yD3H'. + 'j14E+UDQjp24/0E9/eKrbA4HH3aMK1b2ccvXvswjv//1J/s5ud'. + 'Due/hRPfP+OmfOrk7vrn7a48ihA3zh8CH+8Iuffiw/n4r9H1ZZ'. + '0zz7G56hAAAAAElFTkSuQmCC' ; + + //========================================================== + // File: bl_yellow.png + //========================================================== + $this->imgdata_large[2][0]= 1101 ; + $this->imgdata_large[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAB2l'. + 'BMVEX//////////+///+f//9b//8b//73//7X//63//6X//5T/'. + '/4z//4T//3P//2v//1r//0r//0L//zH//yn//yH//xj//xD//w'. + 'j//wD/90L/9zn/9zH/9xj/9xD/9wj/9wD39yn37zn37zH37yH3'. + '7xD37wj37wDv70Lv50rv50Lv5znv5yHv5xjv5wjv5wDn51Ln5x'. + 'Dn3jHn3iHn3hjn3hDn3gje3oze3nPe3lLe1oze1nPe1lLe1ine'. + '1iHe1hje1hDe1gje1gDW1qXW1mvWzqXWzkLWzhjWzhDWzgjWzg'. + 'DOzrXOzq3OzpzOzgDOxkrOxinOxhjOxhDOxgjOxgDGxqXGxnvG'. + 'xmvGvRjGvRDGvQjGvQDFxbnAvr6/v7+9vaW9vZS9vQi9vQC9tR'. + 'C9tQi9tQC7u7W1tZS1tXu1tTG1tQi1rRC1rQi1rQCtrYytrSGt'. + 'rQitrQCtpYStpSGtpQitpQClpYSlpXulpQClnBClnAilnACcnG'. + 'ucnAicnACclAiclACUlFqUlCmUlAiUlACUjFKUjAiUjACMjFKM'. + 'jEqMjACMhACEhACEewB7ezF7exB7ewB7cwBzcylzcwBzaxBzaw'. + 'BraxhrawhrawBrYxBrYwBjYwBjWgBaWgBaUgCXBwRMAAAAAXRS'. + 'TlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAd'. + 'LdfvwAAAAHdElNRQfTAwkRFBKiJZ4hAAAB7ElEQVR4nI3S+1vS'. + 'UBgHcB67WJmIMWAVdDHEDLBC6Go0slj3Ft0m9RRBWQEmFZFDEM'. + 'Qgt0EMFBY7p/+198hj1kM/9N1+++x73rOd6XT/kStnTx4fPzd9'. + 'uwfOjFhomj7smAhwj/6Cm2O0xUwy6g7cCL99uCW3jtBmE7lsdr'. + 'fvejgpzP7uEDFRRoqy2k8xQPnypo2BUMP6waF9Vpf3ciiSzErL'. + 'XTkPc0zDe3bsHDAcc00yoVgqL3UWN2iENpspff+2vn6D0+NnZ9'. + '6lC5K6RuSqBTZn1O/a3rd7v/MSez+WyIpVFX8GuuCA9SjD4N6B'. + 'oRNTfo5PCAVR0fBXoIuOQzab1XjwwNHx00GOj8/nKtV1DdeArk'. + '24R+0ul9PjmbrHPYl+EipyU0OoQSjg8/m83kl/MMhx0fjCkqio'. + 'SMOE7t4JMAzDsizH81AqSdW2hroLPg4/CEF4PhKNx98vlevrbY'. + 'QQXgV6kXwVfjkTiSXmhYVcSa7DIE1DOENe7GM6lUym0l+EXKks'. + 'K20VAeH2M0JvVgrZfL5Qqkiy0lRVaMBd7H7EZUmsiJJcrTdVja'. + 'wGpdbTLj3/3qwrUOjAfGgg4LnNA5tdQx14Hm00QFBm65hfNzAm'. + '+yIFhFtzuj+z2MI/MQn6Uez5pz4Ua41G7VumB/6RX4zMr1TKBr'. + 'SXAAAAAElFTkSuQmCC' ; + + //========================================================== + // File: bl_silver.png + //========================================================== + $this->imgdata_large[3][0]= 1481 ; + $this->imgdata_large[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAMAAAAM7l6QAAADAF'. + 'BMVEUAAADOzs7Gxsa9vb21tbXOxsbOzsbGzsb3///O1ta1vb2c'. + 'paVSWlpKWlpSY2ve5+97hIze7/9aY2vO5/9zhJRaa3tSY3PGzt'. + 'aMlJxrc3tja3NKUlpCSlK1vcZze4RSWmPW5/+Upb3G3v9zhJxS'. + 'Y3t7jKVaa4TO3veltc6ElK1re5Rjc4ycpbV7hJRaY3M5QlLn7/'. + '/Gzt6lrb2EjJzO3v9ja3vG1ve9zu+1xueltdacrc6UpcaMnL1C'. + 'SlqElLV7jK1zhKVre5zW3u/O1ue1vc6ttcaMlKVze4xrc4RSWm'. + 'tKUmPG1v+9zve1xu+tveeltd6crdbe5/+9xt6cpb17hJxaY3s5'. + 'QlrW3vfO1u/Gzue1vdattc6lrcaUnLWMlK2EjKVze5Rrc4xja4'. + 'RSWnNKUmtCSmO9xuecpcZ7hKVaY4TW3v/O1vfGzu+1vd6ttdal'. + 'rc69xu+UnL2MlLWEjK1ze5xrc5R7hK1ja4zO1v+1veettd6lrd'. + 'aMlL3Gzv/39//W1t7Gxs61tb29vcatrbWlpa2cnKWUlJyEhIx7'. + 'e4TW1ufGxta1tcZSUlqcnK3W1u+UlKW9vda1tc57e4ytrcalpb'. + '1ra3vOzu9jY3OUlK29vd6MjKWEhJxaWmtSUmNzc4xKSlpjY3tK'. + 'SmNCQlqUjJzOxs7///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. + 'AAAAAAAAAAAAAAAAAAAAAAAAD///9fnkWVAAAAAnRSTlP/AOW3'. + 'MEoAAAABYktHRP+lB/LFAAAACXBIWXMAAABFAAAARQBP+QatAA'. + 'AB/klEQVR42mNgxAsYqCdd3+lcb4hLmj8wMMvEu8DCMqYbU9op'. + 'UEFB2MTb26eyysomFl06XEEhUCHLpAKo2z/fujikEUVaXUFBMB'. + 'BouLePuV+VVWGRciIXknSEsImCQd3//xwmPr65llaFcSFJHkjS'. + '3iYmWUDZ//8NfCr989NjNUMSUyTg0jneSiaCINn/gmlVQM12qg'. + 'lJnp5waTMTE5NAkCyHWZW/lXWNfUlikmdYK0zax7siS4EDKJtd'. + 'mQeU1XRwLBdLkRGASucWmGVnZ4dnhZvn5lmm29iVOWpnJqcuko'. + 'JKR1Wm5eTkRKYF5eblp9sU2ZeUJiV7zbfVg0pH56UFBQXNjIqK'. + 'jgkujItX1koKTVmYajsdKu2qETVhwgSXiUDZ2Bn9xqUeoZ5e0t'. + 'LzYYZ3B092ndjtOnmKTmycW1s7SHa+l5dtB8zlccE6RlN0dGbM'. + 'mDVbd5KupNBcL6+F82XgHouLj5vRP2PWLGNdd4+ppnxe8tJec6'. + 'XnNsKkm0uVQ5RDRHQTPTym68nPlZbvkfYCexsa5rpJ2qXa5Umm'. + 'ocmec3m8vHjmSs+fgxyhC5JDQ8WSPT2lvbzm8vDIe0nbtiBLN8'. + '8BigNdu1B6Lsje+fPbUFMLi5TMfGmvHi/puUAv23q2YCTFNqH5'. + 'MvPnSwPh3HasCbm3XUpv+nS5VtrkEkwAANSTpGHdye9PAAAASn'. + 'RFWHRzaWduYXR1cmUANGJkODkyYmE4MWZhNTk4MTIyNDJjNjUx'. + 'NzZhY2UxMDAzOGFhZjdhZWIyNzliNTM2ZGFmZDlkM2RiNDU3Zm'. + 'NlNT9CliMAAAAASUVORK5CYII=' ; + + //========================================================== + // File: bl_purple.png + //========================================================== + $this->imgdata_large[4][0]= 1149 ; + $this->imgdata_large[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAACAV'. + 'BMVEX/////////7///5///1v//xv//rf//pf//lP//jP//hP//'. + 'c///a///Wv//Wvf/Uv//Sv//Qv//Qvf/Off/Mf//Kf//If//If'. + 'f/GP//GPf/EP//EPf/CP//CPf/CO//AP//APf3Oe/3Kff3Ke/3'. + 'Ie/3GO/3EO/3AO/vSu/vSufvOefvMefvIefvGOfvEOfvCOfvAO'. + 'fnUufnSufnMd7nId7nGN7nGNbnEN7nCN7nAN7ejN7ejNbec97e'. + 'c9beUtbeQtbeIdbeGNbeENbeCNbeANbWpdbWa9bWQs7WGM7WEM'. + '7WCM7WAM7Otc7Orc7OnM7OSsbOIb3OGMbOEMbOCMbOAM7OAMbG'. + 'pcbGnMbGe8bGa8bGKbXGEL3GCL3GAL3FucXBu73AvsC/v7+9pb'. + '29Ka29GLW9ELW9CLW9AL29ALW5rrm1lLW1e7W1MbW1GKW1EK21'. + 'CLW1CK21AK2tjK2thKWtMaWtIaWtGJytCK2tCKWtAK2tAKWlhK'. + 'Wle6WlEJylCJylAKWlAJyca5ycGJScEJScCJScAJycAJSUWpSU'. + 'UoyUKZSUEIyUCIyUAJSUAIyMUoyMSoyMIYSMEISMCISMAIyMAI'. + 'SECHuEAISEAHt7MXt7EHt7CHt7AHt7AHNzKXNzEGtzAHNzAGtr'. + 'GGtrEGNrCGtrAGtrAGNjCFpjAGNjAFpaAFpaAFIpZn4bAAAAAX'. + 'RSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsS'. + 'AdLdfvwAAAAHdElNRQfTAwkRFB0ymoOwAAAB9UlEQVR4nGNgIA'. + 'K42hhqGtm5+WFIWClKycvLK6gbuARGoEj4aMjLSElISUir6Tt7'. + 'x+aEIWR8leQlwEBSTc/CK7awLguuR0lGQkJMVFRUTFJVzwko1d'. + 'oFk9OQl5IQE+Dh5hVR0TV3CkkvbJgyASJjDZIR5GBl5eRX0TH1'. + 'DEqrbJ2ypBEspSgvJSXKw8bMxMavbOLoGZNf1TZlybw4oIyfLN'. + 'BxotxsLEzsQiaOHkFpBQ2905esrAZK2SpIAaUEuDm5+LTNPAKj'. + 'C+pbps1evrIDKGWnLictKSkuLKyoZQyUya9o7Z2+YMXKGUApew'. + 'M9PTVdXR0TEwf3wOjUirruafOXL18xFyjl72Kpb25qaurg4REU'. + 'EFVe2zJ5zpLlK1aCpbydnZ2dnDwDA6NTopLLeiZNXbB8BcTAyP'. + 'TQ0JDg4KCY1NS83JKmiVOBepYvX9UPlAovzEiPSU/LLyior2vq'. + 'mjZr3vLlIF01IC+XVhUWFlZW1Lc290ycOGfxohVATSsXx4Oksn'. + 'vaWlsb2tq6J0+bM2/RohVA81asbIcEYueU3t7JU6ZNnwNyGkhm'. + '+cp5CRCppJnzZ8+ZM3/JUogECBbBIixr8Yqly8FCy8F6ltUgoj'. + 'lz7sqVK2ByK+cVMSCDxoUrwWDVysXt8WhJKqG4Y8bcuTP6qrGk'. + 'QwwAABiMu7T4HMi4AAAAAElFTkSuQmCC' ; + + //========================================================== + // File: bl_gray.png + //========================================================== + $this->imgdata_large[5][0]= 905 ; + $this->imgdata_large[5][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAABO1'. + 'BMVEX////////3///39/fv7+/e5+fW3t7Wzs7WxsbG1tbGzsbG'. + 'xsbDxMS/v7++wMC+v7+9zsa9xsa9vb29tbW9ra29pa24uLi1xs'. + 'a1vb21tbWxtrattbWmpqalra2cra2cpaWcnJycjIyUpaWUnJyU'. + 'lJSUjIyMnJyMnJSMlJSMlIyMjJSMjIyElJSElIyEjIyEhIR7jI'. + 'x7hIR7hHt7e3t7e3N7e2tzhIRze3tze3Nzc3Nre3trc3Nrc2tr'. + 'a2tjc3Njc2tja3Nja2tjY2NjWlpaa2taY2taY2NaY1paWlpaUl'. + 'JSY2NSY1pSWlpSWlJSUlJSUkpKWlpKWlJKUlpKUlJKUkpKSkpK'. + 'SkJCUlJCUkJCSkpCSkJCQkI5Sko5QkI5Qjk5OUI5OTkxQkIxOT'. + 'kxMTkxMTEpMTEhMTEhKSkYISEpy7AFAAAAAXRSTlMAQObYZgAA'. + 'AAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdE'. + 'lNRQfTAwkRFQfW40uLAAABx0lEQVR4nI3SbXfSMBQA4NV3nce5'. + 'TecAHUywRMHSgFuBCFsQUqwBS1OsWQh0GTj//y8wZUzdwQ/efM'. + 'tzcm/uuXdj4z9ic/PR9k4qk1qDnf0X2/uZzKt8GaRvSubg4LVp'. + 'mkWzCGAT/i3Zsm2XNQHLsm2n2937LaaNnGoJFAEo27B50qN0ay'. + 'Wg26lXsw8fP8nmzcJb2CbsnF5JmmCE8ncN404KvLfsYwd7/MdV'. + 'Pdgl/VbKMIzbuwVgVZw2JlSKJTVJ3609vWUY957lgAUd1KNcqr'. + 'yWnOcOPn8q7d5/8PywAqsOOiVDrn42NFk+HQ7dVuXNYeFdBTpN'. + 'nY5JdZl8xI5Y+HXYaTVqEDp1hAnRohZM03EUjMdhn5wghOoNnD'. + 'wSK7KiiDPqEtz+iD4ctdyAifNYzUnScBSxwPd6GLfRURW7Ay5i'. + 'pS5bmrY8348C5vvUI+TLiIVSJrVA0heK/GDkJxYMRoyfCSmk4s'. + 'uWc3yic/oBo4yF374LGQs5Xw0GyQljI8bYmEsxVUoKxa6HMpAT'. + 'vgyhU2mR8uU1pXmsa8ezqb6U4mwWF/5MeY8uLtQ0nmmQ8UWYvb'. + 'EcJaYWar7QhztrO5Wr4Q4hDbAG/4hfTAF2iCiWrCEAAAAASUVO'. + 'RK5CYII=' ; + + //========================================================== + // File: bl_brown.png + //========================================================== + $this->imgdata_large[6][0]= 1053 ; + $this->imgdata_large[6][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAABoV'. + 'BMVEX////Gzs7GvbXGrZTGpXu9nHO1nHO1nIy9taXGxs7GtaXO'. + 'nHPGlFrGjEq9hEq1hEqte0Klczmcazmce1KtnIzGxsbGvb3OlF'. + 'LOlFq9hFKte0qcc0KUYzGEWimMc1K9ta3OnGvOnGPWnGO9jFq9'. + 'jFKlc0KUazmMYzl7UilzUjGtpZzGxr3GnGPWpWvepXO1hFJ7Wj'. + 'FrSiFjUjG1ra3GnHPvxpT/5733zpythFKUa0KEYzlzUilaOSF7'. + 'Wjm9jErvvYz/99b///f/78bnrYS1hFqle0p7UjFrSiljQiFCMR'. + 'iMhHO9lGvGjFLWnGv/3q3////erXuthEqlc0paQiFKMRhSQin/'. + '1qX/997//++cc0pjSilaQilKORhCKRiclIy9pYzGlGPntYT33q'. + '3vvZSEWjlSOSE5KRB7c2O1lHutczmthFqte1JrWkqtjGtCKRBa'. + 'SjmljGuca0KMYzGMaznOztaclISUYzmEWjFKOSF7a1qEYzFaSi'. + 'GUjISEa0pKOSm9vb2llIxaQhg5IQiEc2tzY0paORilnJy1raVS'. + 'OSljUkJjWkKTpvQWAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHU'. + 'gAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkREiei'. + 'zP2EAAAB9UlEQVR4nGWS/VfSUBjHL5QluhhBxtwyWcCus5Blpm'. + 'wDC4ONaWXCyBi7RMZmpQ2Bypm9W/byV3cHHo/W88s95/s5z/d5'. + 'uwCcCh/4L3zAf+bs0NC588On9QAYGSUuBINk6GI4cmnsBLk8Go'. + '1SFEGMkzRzZeLq5JE8FvDHouw1lqXiCZJOcnCKnx4AcP0GBqmZ'. + 'mRgRT9MMB4Wbs7cGSXNRik3dnp9fiMUzNCNKgpzN9bsaWaQo9s'. + '7dfH7pXiFTZCBU1JK27LmtBO8TDx7mV1eXHqXXyiIUFLWiVzHx'. + 'BxcJIvV4/cn6wkqmWOOwmVE3UQOAp6HxRKL5bGPj+VwhUhalFq'. + '8alm5vAt+LlySZTsebzcKrraIIW4JqZC3N3ga+1+EQTZKZta1M'. + 'pCZCSeDViqVrThsEdsLJZLJYLpZrHVGScrKBvTQNtQHY6XIM02'. + 'E6Ik7odRW1Dzy3N28n3kGuB3tQagm7UMBFXI/sATAs7L5vdbEs'. + '8Lycm923NB0j5wMe6KOsKIIyxcuqauxbrmlqyEWfPmPy5assY1'. + 'U1SvWKZWom9nK/HfQ3+v2HYZSMStayTNN0PYKqg11P1nWsWq7u'. + '4gJeY8g9PLrddNXRdW8Iryv86I3ja/9s26gvukhDdvUQnIjlKr'. + 'IdZCNH+3Xw779qbG63f//ZOzb6C4+ofdbzERrSAAAAAElFTkSu'. + 'QmCC' ; + + //========================================================== + // File: bl_darkgreen.png + //========================================================== + $this->imgdata_large[7][0]= 1113 ; + $this->imgdata_large[7][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAB2l'. + 'BMVEX////////3///v///n/+/e99bW/+/W99bO786/v7++vr69'. + '/96999a7wb24vbu1/9a1zqW1u7itxrWosq6l772l1qWlxrWlxq'. + '2lva2cxpSU562U3q2UxqWUvaWUpZyM77WM57WMvYyMtZyMrZyM'. + 'pZSMnJSEvZyEtYyErZSElIx7zpR7xpx7xpR7vZR7jIRz1pRzxp'. + 'RzjIRrzpRrzoxrxoxrtYRrrYxrrXtrpYRrhHNjzoxjxoxjxoRj'. + 'vYRjtYRjrXtjpXtjlGNje2tazoxazoRaxoxaxoRavYRatYRatX'. + 'tarXtapXNanHNajFpae2tSzoRSxoRSvXtStXtSrXtSrXNSpXNS'. + 'nHNSnGtSlGtSlGNSjGtSjGNKvXtKtXNKrXNKpWtKnGtKlGNKjG'. + 'NKhGNKhFJKc1pKa1JCrWtCpWtCnGtClGNCjGNCjFpChFpCe1JC'. + 'a1JCY1I5pWs5nGM5lGM5jFo5hFo5e1o5c0o5WkoxjFoxhFoxhF'. + 'Ixe1Ixc1Ixc0oxa0ophFIpe0opc0opa0opa0IpY0IpWkIpWjkp'. + 'UkIpUjkhc0oha0IhY0IhWjkhWjEhUjkhUjEhSjEhSikhQjEhQi'. + 'kYWjkYSjEYSikYQjEYQikQSikQQikQQiEQOSExf8saAAAAAXRS'. + 'TlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAd'. + 'LdfvwAAAAHdElNRQfTAwkRFCaDkWqUAAAB+ElEQVR4nI3S+1vS'. + 'UBgHcGZlPV0ks/vFrmQWFimJjiwiYUJWjFBWFhClyZCy5hLrwA'. + 'x2EIwJC1w7zf2vnU0re+iHvs9++7x7zznvORbLf+TA6ct9fYMX'. + 'jrfAUYefpp+/iM1ykxf/lmuhUZ/PTwXC8dml5Wcd23o5H5Mk6b'. + '5NUU8icXbhS67rNzn9JDnguOEYGQtEEtwC+Crs3RJ76P5A/znr'. + 'vsNX7wQnEiwHCtK7TTkW8rvdZ9uJtvZTLkxpHhSrP66bNEj7/P'. + '3WNoLYeeSWQQCIpe9lQw7RNEU5rDsIYtcJ14Nocg7kRUlBNkxn'. + 'YmGKcp7cv3vPwR7XOJPmc0VYU3Sv0e9NOBAYG7Hbz/cMjTMveZ'. + 'CHkqxuTBv0PhYJB4N3XR6PJ5rMAPMnpGUxDX1IxSeMTEaZp1OZ'. + 'nGAIQiYtsalUIhFlmGTy3sO3AizJCKn6DKYryxzHsWyaneMzr6'. + 'cWxRVZVlFTe4SpE3zm+U/4+whyiwJcWVMQNr3XONirVWAklxcE'. + 'EdbqchPhjhVzGpeqhUKhWBQhLElr9fo3pDaQPrw5xOl1CGG1JE'. + 'k1uYEBIVkrb02+o6RItfq6rBhbw/tuINT96766KhuqYpY3UFPF'. + 'BbY/19yZ1XF1U0UNBa9T7rZsz80K0jWk6bpWGW55UzbvTHZ+3t'. + 'vbAv/IT+K1uCmhIrKJAAAAAElFTkSuQmCC' ; + + //========================================================== + // File: bl_green.png + //========================================================== + $this->imgdata_large[8][0]= 1484 ; + $this->imgdata_large[8][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMMFjM4kcoDJQAABVlJREFUeNq9ll2MJFUVx3/11V'. + 'Vd/TE9vU0v4zLDwJIF16jBqLAPhsRXEiDqg0QTJiQSjcSNvCzw'. + 'sBEDDxizhvAAxBgf1oR9QF9NiE9ESFZkQyZB5WtddmdnZ3qqqr'. + 'uqbt367Cofqu3ZZpWVaDzJfbkf53//55z/PVdZXV3l/2H6f7Lp'. + '5VdOV/4Nb+GmHpUeA7AdBNxc3kafNb73jRPK9Xwon8ToxVefqU'. + 'b91wibH5EkCQBCizFihTSviHUHR0hWws9xe3wvJ7/7nPKpgX5y'. + '9oFqt3eOgWniRBoAbUBGGqZUibSYaeoT2B5bnkdaSA6793Cv/S'. + 'QPPbihXBfo5VdOV+8dfgnvwAU62YH5fCZ12sDujFkwyegCqTrB'. + 'iUOKTOJKj8jr88jS8zy6cXwBTP048nuHX0I0nDlIp7RpTG7kM0'. + 'sdyAYsTVukUuWGhlWHMq0ITL92lnUp9R1Obz/GmTNnqn9bDD8/'. + '+0D1oX0O0zQZZDYCsK2j3Gl9jQqDfHiei8GfiKVLlsZkJaBAN1'. + '0i6PgwUbB0GxG5/PrtE/xLRr959Znqw9452oVNI+jiJhnr1pe4'. + 'k29zB1/nFr5Kj7tpt1YYhJ0FJ7nUYbcJQBgahN2MzeCP/OipR6'. + 'prgN6Qr6ELFQFUWoRpNVjlKwxZB8DCpE+PtfEKqV1cUzxpVudu'. + 'GTBHA5Y1g99e+dUio9O/P1Vpq+/WE5GGjDSMoAtAQjrf3C52IP'. + 'QxpY4WK2hpReka9Gfrhqgz0bACRoCWjDh56kQ1z9FeuUUQxVhK'. + 'B92sD1VahM+bAJgcoJhGjP/6Ln8rAgDiRCVRKiIzxMkkodBJ85'. + 'im1IlEHbE4k1xyNveL4YP8HarmGJIOpqyjeQmfNHmTvnqZTWBt'. + 'vIJXpPwlukJSuSTKGK3pEwtJmiX00ZlInTyNscImO6XBITvH1c'. + '8vVt2OucdKvIyeKRTNCivsEMgcpg6taYs30nfq0Gqg6hOSSFJ4'. + 'BSnJPht0IqEjWmOGocEI6F0J94F0qaL6BntTF0MtUfweKQKAPU'. + 'Wwp4OcVnQAmVb0p9DLOzjEhEKnGRmoRc7EzRGlwA6NujAKG4yP'. + '6Sjwc4aVznZ7DK0xXdkDoJf0kGmFBniFBOBGcZSCCSKd0IwN0k'. + 'IS+QZWCGVZex4BnUxya3+Zt9iugQbcRFpIAtuHvAZulPUdLhUJ'. + 'RqegI3WcqaSXddlT3idsWMSRRGkEtNwmyTifAwyBo7LP+11J0e'. + '7tM7pZOYblHkBLcqZ5LcYtw6Wbd4CM3SpE9foYZsIHoqDKCrbz'. + 'mLSQtPwmuhXgtBLs0GBdbXOhFGB7WBKO2F8GXt9/VO97Ya3atF'. + '7nUHnwGjGGQqcPxFEdFqURkEidiZszAERoYIsGju1hq21kWee3'. + 'bw15+8WpsvAy3K1+i3JkkhZyPpxxjjPOsfOYiZ+TFhLPzQnHOU'. + 'tpzGB2dgA4tscIkKIx19Cxg/fPL7vQJu47eXt1VvsDK8pwPueZ'. + 'PuZoQMOqhRoJHSs0kKLBWjvjYinmeQGw1TaX1RFdfZ3LMzYLjA'. + 'C++dkn6AaH2Nobk6cxEzdnuG0TdC8zvdJkN0hqkFkO/jwL0fxa'. + 'so8sBcuFzQ+/+MRC+BeAHnpwQzn++ee5KT9Eshuy46dcKAXm32'. + '0uzPQhS4GttkH2GQID2Wc0Y4LtAbDxhZ/x5A+e/uTG9+jGceXH'. + '9/ySnnIXnUzOxXe1038mW3ZynNmam4yYWkO+f9cv+Oljz16/lV'. + '9tDz/9nerc1hm8ZEScSRK7VvtYl1i1dklsOKyvc+zg/bzw1O8+'. + '/efkajt56kR1ydlEJBc5H46xzbrJ3dY9wrB7hGcff+6/+279L+'. + '0fHxyiE8XMLl4AAAAASUVORK5CYII=' ; + + //========================================================== + // File: bl_blue.png + //========================================================== + $this->imgdata_large[9][0]= 1169 ; + $this->imgdata_large[9][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAACEF'. + 'BMVEX/////////7//35//v1v/exv/Wvf/Wrf/Wpf/Orf+/v7+9'. + 'tc69jP+9hP+5ucW1tc6tlP+rq7Wlpdalpcalpb2cnM6cnMacc/'. + '+cWv+UlLWUjN6UjK2Uc/+Ma/+MUv+EhKWEa/+EQvd7e8Z7e7V7'. + 'e6V7c957Wv9za9Zza8ZzSv9ra5xrSv9rOf9rMe9jUudjQv9jOe'. + '9aWpRaUt5aUpRaSu9aSudSUoxSSs5SSoxSMf9KQtZKOfdKMedK'. + 'Kf9KKe9CKf9CKb1CKa1CIfdCIedCId45MXs5Kfc5If85Iec5Id'. + 'Y5GP8xMbUxMXsxKc4xKZQxIf8xGP8xGO8xGN4xGNYxGL0xGK0p'. + 'KXMpIYwpGP8pGO8pGOcpGNYpGM4pEP8pEPcpEOcpEN4pENYpEM'. + 'YpEL0hGKUhEP8hEPchEO8hEOchEN4hENYhEM4hEMYhELUhCP8h'. + 'CO8hCN4YGJwYGGsYEL0YEK0YEHMYCN4YCM4YCMYYCL0YCKUYAP'. + '8QEJQQEIwQEHsQEGsQCM4QCLUQCK0QCKUQCJwQCJQQCIwQCHMQ'. + 'CGsQAP8QAPcQAO8QAOcQAN4QANYQAM4QAMYQAL0QALUQAKUQAJ'. + 'QQAIQICGsICGMIAO8IANYIAL0IALUIAK0IAKUIAJwIAJQIAIwI'. + 'AIQIAHsIAHMIAGsIAGMAAN4AAMYAAK0AAJQAAIwAAIQAAHMAAG'. + 'sAAGMAAFrR1dDlAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkRFRPMOZ'. + '/2AAAB+klEQVR4nGNgIAIIqeqZmBqpi2JISNml5lVXV3d198Yo'. + 'oUjwm1SnxsbGRsSm5ZfNXO4tjCTjVh0ABhFx6QV9E1Y0S8JkuN'. + '3yAgLc7W3t/QPi4jPKJ8ye1yoIlTKpjvVy15eVUbN0i4zKLJ8w'. + 'ae6qcKgLqmMj3PUFWFl5NJ0CExLLJzbNW7BWCyxlXR0ba6/Axs'. + 'zELmfnkRBT0QiSKgXJCOflxUbYy3KyMHEoOrtEZ1c2TZ6/cMl6'. + 'eaCUamdsbIC7tjgPr4SBS3BMMVDTwkXr1hsDpYy6UmMj/O0tdX'. + 'QNbDxjknJLWqYsXLx0vStQynxGflpkZGCgs7Onp29SbtNkoMy6'. + 'pevCgFJWy3oyMuKjgoKCPWNCvEuqWhcsWrJ06XqQlPnMvrKyrM'. + 'TomJjkZAfHlNa2qdOWrlu63gcopbG8v7+hvLwip7g4JdSxsLZu'. + '8dKlS9ettwBKic2eNXHChIkTG5tKqgpr2uo6loLAehWQx0LnzJ'. + '49p6mpeXLLlNq6RUvqly6dvnR9Bx9ISnnlvLmT582bMr9t4aL2'. + '+vrp60GaDCGB6Ld6wfwFCxYCJZYsXQ+SmL6+FBryInVrFi1atH'. + 'jJkqVQsH6pNCzCJNvXrQW6CmQJREYFEc2CYevXrwMLAyXXl0oz'. + 'IAOt0vVQUGSIkabkDV3DwlzNVDAksAAAfUbNQRCwr88AAAAASU'. + 'VORK5CYII=' ; + + //========================================================== + // File: bs_red.png + //========================================================== + $this->imgdata_small[0][0]= 437 ; + $this->imgdata_small[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAk1'. + 'BMVEX////////GxsbGra3/xsbOhITWhIT/hIT/e3v/c3P/a2vG'. + 'UlK1SkrOUlL/Y2PWUlLGSkrnUlLeSkrnSkr/SkqEGBj/KSmlGB'. + 'jeGBjvGBj3GBj/EBD/CAj/AAD3AADvAADnAADeAADWAADOAADG'. + 'AAC9AAC1AACtAAClAACcAACUAACMAACEAAB7AABzAABrAABjAA'. + 'BuukXBAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. + 'cwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGDNEMgOYAAAAm0'. + 'lEQVR4nI3Q3RKCIBAFYGZMy9RKzX7MVUAUlQTe/+kS0K49d3wD'. + '7JlFaG+CvIR3FvzPXgpLatxevVVS+Jzv0BDGk/UJwOkQ1ph2g/'. + 'Ct5ACX4wNT1o/zzUoJUFUGBiGfVnDTYGJgmrWy8iKEtp0Bpd2d'. + 'jLGu56MB7f4JOOfDJAwoNwslk/jOUi+Jts6RVNrC1hkhPy50Ef'. + 'u79/ADQMQSGQ8bBywAAAAASUVORK5CYII=' ; + + + //========================================================== + // File: bs_lightblue.png + //========================================================== + $this->imgdata_small[1][0]= 657 ; + $this->imgdata_small[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABVl'. + 'BMVEX////////d///AwMC7wcS08P+y+P+xxdCwxM+uws2twMur'. + 'vsinzNynytylzuKhyN6e5v6d5P+d1fOcwNWcu8ub4f+at8iZ3v'. + '+ZvdGY2/yW2f+VscGU1vuT1fqTr72Sx+SSxeKR0fWRz/GPz/OP'. + 'rr+OyeqMy+6Myu2LyeyKxueJudSGw+SGorGDvt+Cvd6CvN2Aud'. + 'p+uNd+t9Z9tdV8tdR8tNN6sc94r813rct2q8h0qcZ0qMVzp8Rx'. + 'o8Bwor5tn7ptnrptnrlsnbhqmbRpmbNpi51ol7Flkqtkkqtkka'. + 'pjj6hijaRhjaZgi6NfiqJfiaFdh55bhJtag5pZgphYgJZYf5VX'. + 'cn9Ve5FSeI1RdopRdYlQdYlPc4dPcoZPcoVNcINLboBLbH9GZn'. + 'hGZXdFZHZEY3RDYnJCXW4/W2s/WWg+Wmo7VmU7VGM7U2E6VGM6'. + 'VGI5UV82T1wGxheQAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHU'. + 'gAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGTok'. + '9Yp9AAAAtElEQVR4nGNgIBaw8wkpKghzwvksPAKiUsraprYiLF'. + 'ARXkE2JiZ1PXMHXzGIAIekOFBE08TGLTCOCyzCLyvDxsZqZOnk'. + 'E56kAhaRV9NQUjW2tPcMjs9wBYsY6Oobmlk7egRGpxZmgkW0zC'. + '2s7Jy9giKT8gohaiQcnVzc/UNjkrMLCyHmcHr7BYREJKTlFxbm'. + 'QOxiEIuKTUzJKgQCaZibpdOzQfwCOZibGRi4dcJyw3S4iQ4HAL'. + 'qvIlIAMH7YAAAAAElFTkSuQmCC' ; + + //========================================================== + // File: bs_gray.png + //========================================================== + $this->imgdata_small[2][0]= 550 ; + $this->imgdata_small[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAMAAADH72RtAAABI1'. + 'BMVEX///8AAAD8EAD8IAD8NAD8RAD8VAAYGBi/v7+goKCCgoJk'. + 'ZGRGRkb8yAD83AD87AD8/AD4+ADo+ADY+ADI+AC0+ACk+ACU+A'. + 'CE+AB0/ABk/ABU/ABE/AAw/AAg/AAQ/AAA/AAA+AAA6BAA2CAA'. + 'yDQAtEQApFQAlGQAhHQAdIgAZJgAVKgARLgAMMgAINwAEOwAAP'. + 'wAAPgIAPAQAOgYAOAkANgsANA0AMg8AMBEALhMALBUAKhcAKBo'. + 'AJhwAJB4AIiAAID////4+Pjy8vLs7Ozm5ubg4ODa2trT09PNzc'. + '3Hx8fBwcG7u7u1tbWurq6oqKiioqKcnJyWlpaQkJCJiYmDg4N9'. + 'fX13d3dxcXFra2tkZGReXl5YWFhSUlJMTExGRkZAQEA1BLn4AA'. + 'AAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIA'. + 'AAsSAdLdfvwAAAAHdElNRQfTAwkUGiIctEHoAAAAfElEQVR4nI'. + '2N2xKDIAwF+bZ2kAa8cNFosBD//yvKWGh9dN+yk9kjxH28R7ze'. + 'wzBOYSX6CaNB927Z9qZ66KTSNmBM7UU9Hx2c5qjmJaWCaV5j4t'. + 'o1ANr40sn5a+x4biElrqHgrXMeac/c1nEpFHG0LSFoo/jO/BeF'. + 'lJnFbT58ayUf0BpA8wAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bs_greenblue.png + //========================================================== + $this->imgdata_small[3][0]= 503 ; + $this->imgdata_small[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAxl'. + 'BMVEX///////+/v79znJQhSkJ7raU5hHtjraVKnJRCjIRClIyU'. + '9++E595avbVaxr2/v7+ctbWcvb17nJxrjIx7paUxQkK9//+Mvb'. + '17ra2Evb17tbVCY2MQGBiU5+ec9/eM5+d71tZanJxjra1rvb1j'. + 'tbVSnJxara1rzs5jxsZKlJRChIQpUlIhQkJatbVSpaU5c3MxY2'. + 'MYMTEQISFavb1Sra1KnJxCjIw5e3sxa2spWlpClJQhSkoYOTkp'. + 'Y2MhUlIQKSkIGBgQMTH+e30mAAAAAXRSTlMAQObYZgAAAAFiS0'. + 'dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfT'. + 'AwkUGTIqLgJPAAAAqklEQVR4nI2QVxOCMBCEM6Mi2OiCvSslJB'. + 'CUoqjn//9TYgCfubf9Zu9uZxFqO+rscO7b6l/LljMZX29J2pNr'. + 'YjmX4ZaIEs2NeiWO19NNacl8rHAyD4LR6jjw6PMRdTjZE0JOiU'. + 'dDv2ALTlzRvSdCCfAHGCc7yRPSrAQRQOWxKc3C/IUjBlDdUcM8'. + '97vFGwBY9QsZGBc/A4DWZNbeXIPWZEZI0c2lqSute/gCO9MXGY'. + '4/IOkAAAAASUVORK5CYII=' ; + + //========================================================== + // File: bs_yellow.png + //========================================================== + $this->imgdata_small[4][0]= 507 ; + $this->imgdata_small[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAzF'. + 'BMVEX///////+/v79zYwCMewDOxoTWzoTezkr/5wj/5wDnzgDe'. + 'xgC1pQCtnACllACcjACUhABjWgDGvVK1rUrOxlLGvUqEexilnB'. + 'jv3hj35xj/7wj/7wD35wDv3gDn1gDezgDWxgDOvQDGtQC9rQCE'. + 'ewB7cwBzawBrYwDWzlLn3lLe1krn3kre1hi9tQC1rQCtpQClnA'. + 'CclACUjACMhAD/9wC/v7///8bOzoT//4T//3v//3P//2v//2Pn'. + '50r//0r//yn39xj//xD//wBjYwDO8noaAAAAAXRSTlMAQObYZg'. + 'AAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAH'. + 'dElNRQfTAwkUGSDZl3MHAAAAqElEQVR4nI3QWRNDMBAA4My09E'. + 'IF1SME0VT1okXvM/3//6kEfbZv+81eswA0DfHxRpOV+M+zkDGG'. + 'rL63zCoJ2ef2RLZDIqNqYexyvFrY9ePkxGWdpvfzC7tEGtIRly'. + 'nqzboFKMlizAXbNnZyiFUKAy4bZ+B6W0lRaQDLmg4h/k7eFwDL'. + 'OWIky8qhXUBQ7gKGmsxpC+ah1TdriwByqG8GQNDNr6kLjf/wAx'. + 'KgEq+FpPbfAAAAAElFTkSuQmCC' ; + + //========================================================== + // File: bs_darkgray.png + //========================================================== + $this->imgdata_small[5][0]= 611 ; + $this->imgdata_small[5][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAMAAAAMCGV4AAABJl'. + 'BMVEX////////o8v/f6O7W4OnR3PXL1OTL0evEyLvCzePAwMC/'. + 'v7a8wsq7t7C1xum1vtS1q6GzopmyxeKsrsOqvNWoq7anvN+nsb'. + 'qhrcGgqbGfpq6cp7+bqMuVmJKRm7yPlKKMnL6FkKWFipOEkLSE'. + 'j6qEhoqAiaB+jqd8haF7hZR4iJt4g5l3hZl2gIt2cod1hJVzeY'. + 'VzboJvhp9sfJJsb41peY1pd5xpdoVod4xndI5lcHxka4BjcYVg'. + 'Z3BfboFbb4lbZnZbYntaZ4laZYVZV3JYYWpXX3JWWm5VX4RVW2'. + 'NUYX9SXHxPWn5OVFxNWWtNVXVMVWFKV3xHUGZGU3dGTldFSlxE'. + 'Sk9ESXBCRlNBS3k/SGs/RU4+R1k9R2U6RFU2PUg0PEQxNU0ECL'. + 'QWAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAA'. + 'CxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGQmbJetrAAAAtklEQV'. + 'R4nGNgwAK4JZTNNOWlYDxhMT4ZDTOzQE1uMF9CiJWVU0LbxDlS'. + 'G8QVF+FnZ2KRNHAIiPUHaZGSlmZj5lH19A1KjLUA8lXU5MWllF'. + 'yjo30TYr2BfG19G11b37CEeN84H38gX1HbwTUkOjo+zjfG3hLI'. + 'l1exCvCNCwnxjfMz0gTyRdXNHXx9fUNCQu2MwU6SN3ZwD42LCH'. + 'W30IK4T8vUJSAkNMhDiwPqYiktXWN9JZj7UQAAjWEfhlG+kScA'. + 'AAAASUVORK5CYII=' ; + + + //========================================================== + // File: bs_darkgreen.png + //========================================================== + $this->imgdata_small[6][0]= 666 ; + $this->imgdata_small[6][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABX1'. + 'BMVEX////////l/+nAwMC86r+8wb28wby8wLy78sCzw7SywrSx'. + 'wLKwvrGuvK+syK+ryq2rx62n36ym3aumxKmk2qij0Keh16ahva'. + 'Og1aSguKKe06KeuaCetZ+d0KGdtZ+bz6Cay56ZyZ2Zwp2Zr5qZ'. + 'rpqYwJuXyZuXrJmVw5mUxZiTxJeTw5eTq5WRwJWPtJKOvZKKuI'. + '6Kt42Kn4yJt42ItIuGsomFsYmEsIiEr4eDr4eBrIR/qoN+qIJ8'. + 'poB7pH56o356on14nnt2nXl0mndzmnZzmXZymHVwlXNvlHJukn'. + 'FtiHBqjm1qjW1oi2toiWpniWplh2hlhmdkhWdig2VggGNgf2Je'. + 'fmFdfGBde19bbl1aeFxXdFpWclhVclhVcVdUcFZTb1VSbVRQal'. + 'JPaVFKY0xKYkxJYUtIYEpHX0lEWkZCWERCV0NCVkM/U0A+U0A+'. + 'UUA+UEA9Uj89UT48Tj45TDvewfrHAAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. + 'RQfTAwkUGRjxlcuZAAAAtElEQVR4nGNgIBZw8osqqIpzw/msfI'. + 'IiUmr6lo6SbFARASEOJiYtQ2uXADmIAJeEGFBE18LBMySBBywi'. + 'LC/LwcFiZuvmH5WiAxZR0tRW1DC3dfYJS8zyAouYGBibWtm7+o'. + 'TEpZfkgEX0rG3snNx9Q2NSCksgaqRd3Ty8gyLiU/NKSiDmcPsF'. + 'BodHJ2UUlZTkQ+xikIlNSE7LLgECZagL2VQyc0H8YnV2uD94jS'. + 'ILIo14iQ4HALarJBNwbJVNAAAAAElFTkSuQmCC' ; + + //========================================================== + // File: bs_purple.png + //========================================================== + $this->imgdata_small[7][0]= 447 ; + $this->imgdata_small[7][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAnF'. + 'BMVEX///////+/v7/Gvca9rb3Grcb/xv+1hLWte629hL21e7XG'. + 'hMbWhNbOe87We9b/hP//e/97OXv/c///a///Y/+cOZz/Sv/WOd'. + 'bnOefvOe//Kf9jCGNrCGv/EP//CP/nCOf/AP/3APfvAO/nAOfe'. + 'AN7WANbOAM7GAMa9AL21ALWtAK2lAKWcAJyUAJSMAIyEAIR7AH'. + 'tzAHNrAGtjAGPP1sZnAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'. + 'HUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGS'. + 'o5QpoZAAAAnElEQVR4nI3Q2xJDMBAG4MyQokWrZz3oSkJISJH3'. + 'f7dK0Gv/Xb7J7vyzCK0NjtPsHuH/2wlhTE7LnTNLCO/TFQjjIp'. + 'hHAA6bY06LSqppMAY47x+04HXTba2kAFlmQKr+YuVDCGUG2k6/'. + 'rNwYK8rKwKCnPxHnVS0aA3rag4UQslUGhrlk0Kpv1+sx3tLZ6w'. + 'dtYemMkOsnz8R3V9/hB87DEu2Wos5+AAAAAElFTkSuQmCC' ; + + + //========================================================== + // File: bs_brown.png + //========================================================== + $this->imgdata_small[8][0]= 677 ; + $this->imgdata_small[8][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABaF'. + 'BMVEX//////////8X/3oD/3nj/1HX/0Gr/xGP/rkv/gBf+iS/2'. + 'bAL1agDxaQDuZwDrZwLpZQDmZQLlZADjcx7gZATeYQDdZgraXw'. + 'DZXwHYXgDXiEvXZAvUjlfUXwXTjVfTbR7ShUvRbR7RWwDMWQDL'. + 'WADKooLKWADJoYLJgkvHWATGoILFn4LFgEvFVgDEZx7EVQDDt6'. + '/DVQDCt6/CnoLChlfCVADAwMC+hFe+UgC8UgC6UQC4gVe4UAC3'. + 'gVe3UAC1gFe1eUu1TwC1TgCzTgCwTQKuTACrSgCqSgCpSgCpSQ'. + 'CodEulSACkRwCiRgCdRACcRACaQwCYQgCWQgKVQQCVQACUQACS'. + 'UR6RPwCOPgCNPQCLPACKPACJOwCEOQCBOAB+NwB9NgB8NgB7NQ'. + 'B6NwJ4NAB3RR52MwB0MgBuLwBtLwBsLwBqLgBpLQBkLQJiKgBh'. + 'KgBgKwRcKABbKQJbJwBaKQRaJwBYKAJVJQDZvdIYAAAAAXRSTl'. + 'MAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLd'. + 'fvwAAAAHdElNRQfTAwkUGho0tvl2AAAAtklEQVR4nGNgIBaoSg'. + 'mLKGpowfkGMty8AqJKpi4mRlAROR5ONg4JFUv3YHOIgDo/HwsT'. + 'q6yps29EsjZYREFIkJ2ZS9/OMzA20wEsIi8uKSZtaOPmH5WSFw'. + 'YW0VRW07Vw8vCLSMguLwCL6FlaObp6B0TGZxSXQ9TouHv6+IXG'. + 'JGYWlpdDzNEKCgmPjkvLKS0vL4LYxWAen5SelV8OBNZQFxrZ5h'. + 'aC+GX2MDczMBh7pZakehkTHQ4AA0Am/jsB5gkAAAAASUVORK5C'. + 'YII=' ; + + //========================================================== + // File: bs_blue.png + //========================================================== + $this->imgdata_small[9][0]= 436 ; + $this->imgdata_small[9][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAk1'. + 'BMVEX///////+/v7+trcbGxv+EhM6EhNaEhP97e/9zc/9ra/9S'. + 'UsZKSrVSUs5jY/9SUtZKSsZSUudKSt5KSudKSv8YGIQpKf8YGK'. + 'UYGN4YGO8YGPcQEP8ICP8AAP8AAPcAAO8AAOcAAN4AANYAAM4A'. + 'AMYAAL0AALUAAK0AAKUAAJwAAJQAAIwAAIQAAHsAAHMAAGsAAG'. + 'ONFkFbAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. + 'cwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGhNNakHSAAAAmk'. + 'lEQVR4nI3P2xKCIBAGYGfM6SBWo1nauIqogaDA+z9dK9Lhrv47'. + 'vtl/2A2CfxNlJRRp9IETYGraJeEb7ocLNKznia8A7Db7umWDUG'. + 'sxAzhurxRHxok4KQGqCuEhlL45oU1D2w5BztY4KRhj/bCAsetM'. + '2uObjwvY8/oX50JItYDxSyZSTrO2mNhvGMbaWAevnbFIcpuTr7'. + 't+5AkyfBIKSJHdSQAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bs_green.png + //========================================================== + $this->imgdata_small[10][0]= 452 ; + $this->imgdata_small[10][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAn1'. + 'BMVEX///////+/v7+/v7/G/8aUxpSMvYyUzpSMzoyM1oxarVqE'. + '/4R7/3tavVpKnEpaxlpz/3Nr/2tKtUpj/2Na51pKzkpK1kpK50'. + 'pK/0oYcxgp/ykYlBgY3hgY7xgY9xgQ/xAI/wgA/wAA9wAA7wAA'. + '5wAA3gAA1gAAzgAAxgAAvQAAtQAArQAApQAAnAAAlAAAjAAAhA'. + 'AAewAAcwAAawAAYwA0tyxUAAAAAXRSTlMAQObYZgAAAAFiS0dE'. + 'AIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAw'. + 'kUGgW5vvSDAAAAnklEQVR4nI3QSxKCMAwA0M4gqCgoiiJ+kEAL'. + 'LQUq0PufzX7ENdnlJZNkgtDS2CYZvK6bf+7EoKLA9cH5SQzv6A'. + 'YloTywsAbYr44FrlgrXCMJwHl3xxVtuuFkJAPIcw2tGB9GcFli'. + 'oqEf5GTkSUhVMw2TtD0XSlnDOw3SznE5520vNEi7CwW9+Ayjyq'. + 'U/3+yPuq5gvhkhL0xlGnqL//AFf14UIh4mkEkAAAAASUVORK5C'. + 'YII=' ; + + + //========================================================== + // File: bs_white.png + //========================================================== + $this->imgdata_small[11][0]= 480 ; + $this->imgdata_small[11][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAYAAADwMZRfAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMLFTsY/ewvBQAAAW1JREFUeJytkz2u4jAUhT/jic'. + 'gfBUKiZhE0bIKeVbCWrIKenp6eDiGlCEEEBArIxvzGU4xeZjLk'. + 'jWb05lRXuvbx+exr4bouX1Xjyw7Atz81F4uFBYjjGIDhcCjq1o'. + 'k6nN1uZwFerxfP55Msy1itVmRZBsB4PK6YveHkeW5d18XzPIIg'. + 'wPd9Wq0WnU6HMAxJkoQoiuynOIfDwUopkVIihKAoCgAcx6Hdbm'. + 'OMIU1T5vN55eBKEikljUYDIX6kFUKU9e8aDAZlmjcca+1b7TgO'. + '1+uVy+VS9nzfr8e53++VzdZaiqIgz3OMMWitOZ/PaK0JgqDeRC'. + 'mF53lIKYGfr3O73TDGoJQiTVO01nS73XqT4/FIs9kkCAIej0eZ'. + 'brPZEMcxSZKgtQZgMpmIWpN+vy+m06n1PK9yTx8Gy+WS/X5Pr9'. + 'er9GuHLYoiG4YhSilOpxPr9Zrtdlti/JriU5MPjUYjq7UuEWaz'. + '2d+P/b/qv/zi75oetJcv7QQXAAAAAElFTkSuQmCC' ; + + + //========================================================== + // File: bs_cyan.png + //========================================================== + $this->imgdata_small[12][0]= 633 ; + $this->imgdata_small[12][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABPl'. + 'BMVEX////////F///AwMCvxsaC1NSC0dGCz8+CzMyA//94//91'. + '//9q//9j//9X4uJX09NXz89Xx8dXxMRL//9L5uZL3d1L2NhLxs'. + 'ZLt7cv//8e9fUe8fEe7u4e398epqYehoYX//8L+PgK//8F9fUE'. + '/v4E5+cEb28EZ2cC//8C/v4C/f0CzMwCrq4Cjo4CdXUCaWkCZW'. + 'UB/PwA//8A/f0A+/sA8/MA7e0A7OwA6+sA5eUA5OQA4uIA4eEA'. + '3NwA2toA2NgA1dUA09MA0tIA0NAAysoAxsYAxcUAxMQAv78Avr'. + '4AvLwAtrYAtbUAs7MAsLAAra0Aq6sAqKgApaUApKQAoqIAoKAA'. + 'n58AmpoAlZUAk5MAkpIAkJAAj48AjIwAiYkAh4cAf38AfX0Ae3'. + 'sAenoAcnIAcHAAa2sAaWkAaGgAYmIUPEuTAAAAAXRSTlMAQObY'. + 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. + 'AHdElNRQfTAwkUGQDi+VPPAAAAtElEQVR4nGNgIBawikipyIiy'. + 'wfksfJpGRkamNtr8LFARPiMFHmFDcztXfwGoFi0jLiZuZRtnry'. + 'BddrCIiJEGL6eklYO7X3iCOFhE2thESdHawdUnJDZFDiyiamZh'. + 'aevk5h0UlZSpBhaRtbN3dPHwDY5MSM+EqBFzc/f0DgiLTkjLzI'. + 'SYw6bjHxgaEZeckZmpD7GLQSAqJj4xNRMIBGFuFtRLA/ENhGBu'. + 'ZmDgkJBXl5fgIDocAAKcINaFePT4AAAAAElFTkSuQmCC' ; + + //========================================================== + // File: bs_bluegreen.png + //========================================================== + $this->imgdata_small[13][0]= 493 ; + $this->imgdata_small[13][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAvV'. + 'BMVEX///////+/v79j//855/8x3v851v9Spb1C1v8AOUqEtcZK'. + 'lK1StdYxzv8hxv8AY4QASmNSlK1KpcZKtd4YQlIYnM4YrecIvf'. + '8AtfcAre8AjL0AhLUAc5wAa5QAWnsAQloAKTkAGCFKhJxKrdYY'. + 'jL0Ypd4Atf8ArfcApecAnN4AlM4AjMYAe60Ac6UAY4wAUnNSnL'. + '0AlNYAWoQASmsAOVIAITGEtc4YWnsAUnsAMUqtvcaErcYAKUIA'. + 'GCkAECHUyVh/AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAA'. + 'AJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGxNUcXCT'. + 'AAAAqUlEQVR4nI2Q1xKCMBREM2NHLCCogAGCjd6SqLT8/2cZKT'. + '6zb3tm987OBWCsXoejp8rC35fi4+l6gXFZlD0Rz6fZ1tdDmKR9'. + 'RdOmkzmP7DDpilfX3SzvRgQ/Vr1uiZplfsCBiVf03RJd140wgj'. + 'kmNqMtuYXcxyYmNWJdRoYwzpM9qRvGujuCmSR7q7ARY00/MiWk'. + 'sCnjkobNEm1+HknDZgAqR0GKU43+wxdu2hYzbsHU6AAAAABJRU'. + '5ErkJggg==' ; + + //========================================================== + // File: bs_lightred.png + //========================================================== + $this->imgdata_small[14][0]= 532 ; + $this->imgdata_small[14][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAA3l'. + 'BMVEX///////+/v7/Gvb0hGBj/5///3v//zu//1u//xucpGCG9'. + 'nK21lKVSQkp7Wms5KTExISlaOUpjQlIhEBj/tdbOhKXnrcbGjK'. + 'Wla4TetcbGnK2EWmv/rc73pcZ7UmOcY3vOpbW1jJzenLW9e5Rz'. + 'Slq1c4xrQlJSOULGhJz/pcb3nL2chIzOnK33rcbelK3WjKWMWm'. + 'vGe5SEUmM5ISnOtb3GrbXerb3vpb2ca3v/rcaUY3POhJxCKTF7'. + 'SlrWnK21e4ytc4TvnLXnlK2la3taOUK1lJxrSlLGhJRjQkpSMT'. + 'lw+q2nAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. + 'cwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGjoP2Nm+AAAAr0'. + 'lEQVR4nGNgIBaYiOk62imYwPnMkiIyso76yhJSzFARMxkRNk49'. + 'a3t5OW6oFk1LVkYOfWUHKxUXiEYzLS12DnN3VXkjIRtFsIiSk5'. + '6evqGqhYGKugAfWMRa1FpD2UHeQEXQRlgALCJur+rgbCUNFOAS'. + 'hqjRkZe3MpBTcwEKCEPMMTGSs3Xz8OQHCnBBHckt6OJpIyAMBD'. + 'wwN/MYc4H4LK4wNzMwmGrzcvFqmxIdDgDiHRT6VVQkrAAAAABJ'. + 'RU5ErkJggg==' ; + + //========================================================== + // File: bxs_lightred.png + //========================================================== + $this->imgdata_xsmall[0][0]= 432 ; + $this->imgdata_xsmall[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAA3l'. + 'BMVEX///////+/v7/Gvb0hGBj/5///3v//zu//1u//xucpGCG9'. + 'nK21lKVSQkp7Wms5KTExISlaOUpjQlIhEBj/tdbOhKXnrcbGjK'. + 'Wla4TetcbGnK2EWmv/rc73pcZ7UmOcY3vOpbW1jJzenLW9e5Rz'. + 'Slq1c4xrQlJSOULGhJz/pcb3nL2chIzOnK33rcbelK3WjKWMWm'. + 'vGe5SEUmM5ISnOtb3GrbXerb3vpb2ca3v/rcaUY3POhJxCKTF7'. + 'SlrWnK21e4ytc4TvnLXnlK2la3taOUK1lJxrSlLGhJRjQkpSMT'. + 'lw+q2nAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. + 'cwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUKBOgGhWjAAAAS0'. + 'lEQVR4nGNgQAEmunYmEJaMCKe1vBxYzJKVQ9lKBSSupKdnaKGi'. + 'zgdkiqs6WKnYcIGYJnK2HvzCwmCNgi42wsLCECNMeXlNUY0HAL'. + 'DaB7Du8MiEAAAAAElFTkSuQmCC' ; + + //========================================================== + // File: bxs_bluegreen.png + //========================================================== + $this->imgdata_xsmall[1][0]= 397 ; + $this->imgdata_xsmall[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAvV'. + 'BMVEX///////+/v79j//855/8x3v851v9Spb1C1v8AOUqEtcZK'. + 'lK1StdYxzv8hxv8AY4QASmNSlK1KpcZKtd4YQlIYnM4YrecIvf'. + '8AtfcAre8AjL0AhLUAc5wAa5QAWnsAQloAKTkAGCFKhJxKrdYY'. + 'jL0Ypd4Atf8ArfcApecAnN4AlM4AjMYAe60Ac6UAY4wAUnNSnL'. + '0AlNYAWoQASmsAOVIAITGEtc4YWnsAUnsAMUqtvcaErcYAKUIA'. + 'GCkAECHUyVh/AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAA'. + 'AJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUKDVyF5Be'. + 'AAAASUlEQVR4nGNgQAFmYqJcEJaEOJ+UrD5YTJKFTZrfGCQuaq'. + 'glLWvMaQ5kqujo6hnbKIKYXPr68gp2dmCNJiZAlh3ECGsREWtU'. + '4wF1kwdpAHfnSwAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bxs_navy.png + //========================================================== + $this->imgdata_xsmall[2][0]= 353 ; + $this->imgdata_xsmall[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAk1'. + 'BMVEX///////+/v7+trcbGxv+EhM6EhNaEhP97e/9zc/9ra/9S'. + 'UsZKSrVSUs5jY/9SUtZKSsZSUudKSt5KSudKSv8YGIQpKf8YGK'. + 'UYGN4YGO8YGPcQEP8ICP8AAP8AAPcAAO8AAOcAAN4AANYAAM4A'. + 'AMYAAL0AALUAAK0AAKUAAJwAAJQAAIwAAIQAAHsAAHMAAGsAAG'. + 'ONFkFbAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. + 'cwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUJxXO4axZAAAAR0'. + 'lEQVR4nGNgQAGskhKsEJaslIi8ijpYTJaDU1FVAyQuKSujoKKh'. + 'LQ5kSigpqWro6oOYrOoaWroGBmCNWiCWAdQwUVFWVOMBOp4GCJ'. + 's5S60AAAAASUVORK5CYII=' ; + + //========================================================== + // File: bxs_gray.png + //========================================================== + $this->imgdata_xsmall[3][0]= 492 ; + $this->imgdata_xsmall[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABI1'. + 'BMVEX///8AAAD8EAD8IAD8NAD8RAD8VAAYGBi/v7+goKCCgoJk'. + 'ZGRGRkb8yAD83AD87AD8/AD4+ADo+ADY+ADI+AC0+ACk+ACU+A'. + 'CE+AB0/ABk/ABU/ABE/AAw/AAg/AAQ/AAA/AAA+AAA6BAA2CAA'. + 'yDQAtEQApFQAlGQAhHQAdIgAZJgAVKgARLgAMMgAINwAEOwAAP'. + 'wAAPgIAPAQAOgYAOAkANgsANA0AMg8AMBEALhMALBUAKhcAKBo'. + 'AJhwAJB4AIiAAID////4+Pjy8vLs7Ozm5ubg4ODa2trT09PNzc'. + '3Hx8fBwcG7u7u1tbWurq6oqKiioqKcnJyWlpaQkJCJiYmDg4N9'. + 'fX13d3dxcXFra2tkZGReXl5YWFhSUlJMTExGRkZAQEA1BLn4AA'. + 'AAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEA'. + 'AAsRAX9kX5EAAAAHdElNRQfTAwkUKC74clmyAAAAQklEQVR4nG'. + 'NgQAVBYVCGt5dXYEQ0mOnp5h4QFgVmeri6+4dHxYMVeHoFRUTH'. + 'gTUFBIZBWAwMkZEx8bFQM2Lj0UwHANc/DV6yq/BiAAAAAElFTk'. + 'SuQmCC' ; + + //========================================================== + // File: bxs_graypurple.png + //========================================================== + $this->imgdata_xsmall[4][0]= 542 ; + $this->imgdata_xsmall[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABSl'. + 'BMVEX////////11P/MqdvKrNfAwMC+u7+9u7+4rr24lsi3rby3'. + 'lMe1rLq1o720q7i0oL20ksSzoryyqbaykMGxlb2wkL+vnbiujb'. + '2sjLuri7qpl7GoirWoibenmK2mla6mjLKmhrSllauki7CjhrCj'. + 'hLGihLChg6+ggq2fkqadkKOcfqqai6Gag6WYe6WXeqSWeaOTd6'. + 'CTd5+Rdp6RdZ6RdZ2Qg5eOc5qMcpiLcZeJb5WIbpOHbZKGbJGE'. + 'a4+CaY2AZ4t/Z4p/Zop/Zol+Zol7ZIZ6Y4V5YoR1ZH11X391Xn'. + '9zXX1yXXtxXHtvWnluWXhsV3VqVnNpVXJoVHFnU3BmUm9jUGth'. + 'VGdgTmheTGZcS2RcSmRaSWJYR19XRl5SQllRQlhQQVdPQFZOP1'. + 'VLPlFJO09IPE5IOk5FOEtEN0lDOEpDOElDNklCNkc/M0XhbrfD'. + 'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACx'. + 'EAAAsRAX9kX5EAAAAHdElNRQfTAwkUKCgREfyHAAAATUlEQVR4'. + 'nGNgQAEcIko8EBY3M5Ougy+IxSXMwmTsFsAHZMqrSRvZB0W7A5'. + 'k6FlYugXEZICaPr394Um4uSAFDRFRCbm4uxAihsDAhVOMBHT0L'. + 'hkeRpo8AAAAASUVORK5CYII=' ; + + //========================================================== + // File: bxs_red.png + //========================================================== + $this->imgdata_xsmall[5][0]= 357 ; + $this->imgdata_xsmall[5][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAk1'. + 'BMVEX////////GxsbGra3/xsbOhITWhIT/hIT/e3v/c3P/a2vG'. + 'UlK1SkrOUlL/Y2PWUlLGSkrnUlLeSkrnSkr/SkqEGBj/KSmlGB'. + 'jeGBjvGBj3GBj/EBD/CAj/AAD3AADvAADnAADeAADWAADOAADG'. + 'AAC9AAC1AACtAAClAACcAACUAACMAACEAAB7AABzAABrAABjAA'. + 'BuukXBAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. + 'cwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUIyjy5SVMAAAAS0'. + 'lEQVR4nGNgQAFsUpJsEJastIi8ijpYTJaDU0FVgxXIlJKVUVDR'. + '0BYHMiUUlVQ1dPVBTDZ1dS1dAwOQAgYtbSDLAGIEq6goK6rxAD'. + 'yXBg73lwGUAAAAAElFTkSuQmCC' ; + + //========================================================== + // File: bxs_yellow.png + //========================================================== + $this->imgdata_xsmall[6][0]= 414 ; + $this->imgdata_xsmall[6][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAzF'. + 'BMVEX///////+/v79zYwCMewDOxoTWzoTezkr/5wj/5wDnzgDe'. + 'xgC1pQCtnACllACcjACUhABjWgDGvVK1rUrOxlLGvUqEexilnB'. + 'jv3hj35xj/7wj/7wD35wDv3gDn1gDezgDWxgDOvQDGtQC9rQCE'. + 'ewB7cwBzawBrYwDWzlLn3lLe1krn3kre1hi9tQC1rQCtpQClnA'. + 'CclACUjACMhAD/9wC/v7///8bOzoT//4T//3v//3P//2v//2Pn'. + '50r//0r//yn39xj//xD//wBjYwDO8noaAAAAAXRSTlMAQObYZg'. + 'AAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAH'. + 'dElNRQfTAwkUIzoBXFQEAAAAS0lEQVR4nGNgQAFsDhJsEJaTo5'. + '2skj5YzMnSSk7ZwBzIlOSUklPiMxYHMnW4FXT5VNVBTDZeXiNV'. + 'QUGQAgYBYyBLEGIEq5gYK6rxAH4kBmHBaMQQAAAAAElFTkSuQm'. + 'CC' ; + + //========================================================== + // File: bxs_greenblue.png + //========================================================== + $this->imgdata_xsmall[7][0]= 410 ; + $this->imgdata_xsmall[7][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAxl'. + 'BMVEX///////+/v79znJQhSkJ7raU5hHtjraVKnJRCjIRClIyU'. + '9++E595avbVaxr2/v7+ctbWcvb17nJxrjIx7paUxQkK9//+Mvb'. + '17ra2Evb17tbVCY2MQGBiU5+ec9/eM5+d71tZanJxjra1rvb1j'. + 'tbVSnJxara1rzs5jxsZKlJRChIQpUlIhQkJatbVSpaU5c3MxY2'. + 'MYMTEQISFavb1Sra1KnJxCjIw5e3sxa2spWlpClJQhSkoYOTkp'. + 'Y2MhUlIQKSkIGBgQMTH+e30mAAAAAXRSTlMAQObYZgAAAAFiS0'. + 'dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfT'. + 'AwkUJy5/6kV9AAAATUlEQVR4nGNgQAGCyuyCEJaGugKHviVYzF'. + 'hO3sxCWwDIVNLTM9PXtpEGMhW12Cy0DR1ATEFLSxZ7BweQAgYd'. + 'HUMHBweIEQKiogKoxgMAo/4H5AfSehsAAAAASUVORK5CYII=' ; + + //========================================================== + // File: bxs_purple.png + //========================================================== + $this->imgdata_xsmall[8][0]= 364 ; + $this->imgdata_xsmall[8][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAnF'. + 'BMVEX///////+/v7/Gvca9rb3Grcb/xv+1hLWte629hL21e7XG'. + 'hMbWhNbOe87We9b/hP//e/97OXv/c///a///Y/+cOZz/Sv/WOd'. + 'bnOefvOe//Kf9jCGNrCGv/EP//CP/nCOf/AP/3APfvAO/nAOfe'. + 'AN7WANbOAM7GAMa9AL21ALWtAK2lAKWcAJyUAJSMAIyEAIR7AH'. + 'tzAHNrAGtjAGPP1sZnAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'. + 'HUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUIj'. + 'mBTjT/AAAASUlEQVR4nGNgQAGskhKsEJaCrJiSuhZYTEFASFlD'. + 'GyQuqSCnrK6tJwpkiquoamgbGIGYrFpaugbGxmCNunpAljHECB'. + 'ZBQRZU4wFSMAZsXeM71AAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bxs_green.png + //========================================================== + $this->imgdata_xsmall[9][0]= 370 ; + $this->imgdata_xsmall[9][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAn1'. + 'BMVEX///////+/v7+/v7/G/8aUxpSMvYyUzpSMzoyM1oxarVqE'. + '/4R7/3tavVpKnEpaxlpz/3Nr/2tKtUpj/2Na51pKzkpK1kpK50'. + 'pK/0oYcxgp/ykYlBgY3hgY7xgY9xgQ/xAI/wgA/wAA9wAA7wAA'. + '5wAA3gAA1gAAzgAAxgAAvQAAtQAArQAApQAAnAAAlAAAjAAAhA'. + 'AAewAAcwAAawAAYwA0tyxUAAAAAXRSTlMAQObYZgAAAAFiS0dE'. + 'AIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAw'. + 'kUKBrZxq0HAAAATElEQVR4nGNgQAGccrIcEJaivISyhjaIxa7I'. + 'I6CiqcMKZMopKqho6OhLA5kyqmqaOobGICartraeoYkJSAGDnj'. + '6QZQIxgk1Skg3VeABlVgbItqEBUwAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bxs_darkgreen.png + //========================================================== + $this->imgdata_xsmall[10][0]= 563 ; + $this->imgdata_xsmall[10][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABX1'. + 'BMVEX////////l/+nAwMC86r+8wb28wby8wLy78sCzw7SywrSx'. + 'wLKwvrGuvK+syK+ryq2rx62n36ym3aumxKmk2qij0Keh16ahva'. + 'Og1aSguKKe06KeuaCetZ+d0KGdtZ+bz6Cay56ZyZ2Zwp2Zr5qZ'. + 'rpqYwJuXyZuXrJmVw5mUxZiTxJeTw5eTq5WRwJWPtJKOvZKKuI'. + '6Kt42Kn4yJt42ItIuGsomFsYmEsIiEr4eDr4eBrIR/qoN+qIJ8'. + 'poB7pH56o356on14nnt2nXl0mndzmnZzmXZymHVwlXNvlHJukn'. + 'FtiHBqjm1qjW1oi2toiWpniWplh2hlhmdkhWdig2VggGNgf2Je'. + 'fmFdfGBde19bbl1aeFxXdFpWclhVclhVcVdUcFZTb1VSbVRQal'. + 'JPaVFKY0xKYkxJYUtIYEpHX0lEWkZCWERCV0NCVkM/U0A+U0A+'. + 'UUA+UEA9Uj89UT48Tj45TDvewfrHAAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElN'. + 'RQfTAwkUKCFozUQjAAAATUlEQVR4nGNgQAGcoqrcEJYQB5OhSw'. + 'CIxSXGwWThGcIDZCppK5o7hyV6AZl6NnbuoSmFICZ3YHB0RkkJ'. + 'SAFDbEJaSUkJxAjeyEheVOMBQj4MOEkWew4AAAAASUVORK5CYI'. + 'I=' ; + + //========================================================== + // File: bxs_cyan.png + //========================================================== + $this->imgdata_xsmall[11][0]= 530 ; + $this->imgdata_xsmall[11][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABPl'. + 'BMVEX////////F///AwMCvxsaC1NSC0dGCz8+CzMyA//94//91'. + '//9q//9j//9X4uJX09NXz89Xx8dXxMRL//9L5uZL3d1L2NhLxs'. + 'ZLt7cv//8e9fUe8fEe7u4e398epqYehoYX//8L+PgK//8F9fUE'. + '/v4E5+cEb28EZ2cC//8C/v4C/f0CzMwCrq4Cjo4CdXUCaWkCZW'. + 'UB/PwA//8A/f0A+/sA8/MA7e0A7OwA6+sA5eUA5OQA4uIA4eEA'. + '3NwA2toA2NgA1dUA09MA0tIA0NAAysoAxsYAxcUAxMQAv78Avr'. + '4AvLwAtrYAtbUAs7MAsLAAra0Aq6sAqKgApaUApKQAoqIAoKAA'. + 'n58AmpoAlZUAk5MAkpIAkJAAj48AjIwAiYkAh4cAf38AfX0Ae3'. + 'sAenoAcnIAcHAAa2sAaWkAaGgAYmIUPEuTAAAAAXRSTlMAQObY'. + 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAA'. + 'AHdElNRQfTAwkUKQFKuFWqAAAATUlEQVR4nGNgQAGsUjJsEJaR'. + 'grC5qz9YzIiL28YriB3IlDZRsnYNiZUDMmXtHT2CE9JBTDb/wI'. + 'jkzEyQAoaomMTMzEyIERzy8hyoxgMAN2MLVPW0f4gAAAAASUVO'. + 'RK5CYII=' ; + + //========================================================== + // File: bxs_orange.png + //========================================================== + $this->imgdata_xsmall[12][0]= 572 ; + $this->imgdata_xsmall[12][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABaF'. + 'BMVEX//////////8X/3oD/3nj/1HX/0Gr/xGP/rkv/gBf+iS/2'. + 'bAL1agDxaQDuZwDrZwLpZQDmZQLlZADjcx7gZATeYQDdZgraXw'. + 'DZXwHYXgDXiEvXZAvUjlfUXwXTjVfTbR7ShUvRbR7RWwDMWQDL'. + 'WADKooLKWADJoYLJgkvHWATGoILFn4LFgEvFVgDEZx7EVQDDt6'. + '/DVQDCt6/CnoLChlfCVADAwMC+hFe+UgC8UgC6UQC4gVe4UAC3'. + 'gVe3UAC1gFe1eUu1TwC1TgCzTgCwTQKuTACrSgCqSgCpSgCpSQ'. + 'CodEulSACkRwCiRgCdRACcRACaQwCYQgCWQgKVQQCVQACUQACS'. + 'UR6RPwCOPgCNPQCLPACKPACJOwCEOQCBOAB+NwB9NgB8NgB7NQ'. + 'B6NwJ4NAB3RR52MwB0MgBuLwBtLwBsLwBqLgBpLQBkLQJiKgBh'. + 'KgBgKwRcKABbKQJbJwBaKQRaJwBYKAJVJQDZvdIYAAAAAXRSTl'. + 'MAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9k'. + 'X5EAAAAHdElNRQfTAwkUJBSSy88MAAAATUlEQVR4nGNgQAGqwo'. + 'paEBYPJ4eKezCIpc7HwmrqG6ENZMpLihm6RaWEAZl6Vo7ekRnF'. + 'IKZWSHhcTnk5SAFDfFJWeXk5xAjj1FRjVOMBeFwNcWYSLjsAAA'. + 'AASUVORK5CYII=' ; + + //========================================================== + // File: bxs_lightblue.png + //========================================================== + $this->imgdata_xsmall[13][0]= 554 ; + $this->imgdata_xsmall[13][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABVl'. + 'BMVEX////////d///AwMC7wcS08P+y+P+xxdCwxM+uws2twMur'. + 'vsinzNynytylzuKhyN6e5v6d5P+d1fOcwNWcu8ub4f+at8iZ3v'. + '+ZvdGY2/yW2f+VscGU1vuT1fqTr72Sx+SSxeKR0fWRz/GPz/OP'. + 'rr+OyeqMy+6Myu2LyeyKxueJudSGw+SGorGDvt+Cvd6CvN2Aud'. + 'p+uNd+t9Z9tdV8tdR8tNN6sc94r813rct2q8h0qcZ0qMVzp8Rx'. + 'o8Bwor5tn7ptnrptnrlsnbhqmbRpmbNpi51ol7Flkqtkkqtkka'. + 'pjj6hijaRhjaZgi6NfiqJfiaFdh55bhJtag5pZgphYgJZYf5VX'. + 'cn9Ve5FSeI1RdopRdYlQdYlPc4dPcoZPcoVNcINLboBLbH9GZn'. + 'hGZXdFZHZEY3RDYnJCXW4/W2s/WWg+Wmo7VmU7VGM7U2E6VGM6'. + 'VGI5UV82T1wGxheQAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHU'. + 'gAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUJziL'. + 'PvAsAAAATUlEQVR4nGNgQAHsQgqcEJYgG5Oegy+IxSHOxmTiFs'. + 'gFZMprKBnbB8e7AplaFlbOQUl5ICanX0BEWmEhSAFDVGxKYWEh'. + 'xAjusDBuVOMBJO8LrFHRAykAAAAASUVORK5CYII=' ; + + //========================================================== + // File: bxs_darkgray.png + //========================================================== + $this->imgdata_xsmall[14][0]= 574 ; + $this->imgdata_xsmall[14][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABm'. + 'JLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsRAAALEQF/ZF+RAAAB'. + 'iElEQVR42k3QPU8TYRwA8P//ebkXrgdIColXRAOEkJqbaExMut'. + 'DBhE1GNjYHPg+DG6ODiU6QOLjVxITBcFKBYCstlAC2Bz17fe76'. + 'vLD6+wg/1FpTRFR5lpaub/u1eGBGaAT4HneD4OlXx7avtDYUjT'. + 'HQabd2Ti8e3vVSKzxrtHS32wIpFVldno22Nqvvg2Bhl0gp/aNm'. + 'vJ3qqXAtLIva+ks1H0wqlSXi4+d6+OFTfRsAfHJx2d1od24rZP'. + 'xP2HzopINr1mkesX7ccojqif0v9crxWXODZTno3+dNGA7uWLsd'. + 'mUYU4fHJCViMG9umLBmM4L6fagZGg9QKfjZ+Qfy3C3G/B3mugF'. + 'IHHNcDf64E3KJALApk2p8CSolUUqLjFkyxOGMsTtFyJ+Wz57NQ'. + '8DghS4sLB0svioeZZo7nPhFoUKZDIVFbglkTTnl5/rC8snjAkJ'. + 'Bk/XV5LxHC/v7tR8jzTFPbg8LENK9WX0Vv31T2AEmCSmlKCCoh'. + 'ROnP1U1tPFYjJBRcbtzSf+GPsFTAQBq1n4AAAABKdEVYdHNpZ2'. + '5hdHVyZQBiYzYyMDIyNjgwYThjODMyMmUxNjk0NWUzZjljOGFh'. + 'N2VmZWFhMjA4OTE2ZjkwOTdhZWE1MzYyMjk0MWRkM2I5EqaPDA'. + 'AAAABJRU5ErkJggg==' ; + } +} + +?> diff --git a/src/classes/jpgraph/imgdata_bevels.inc.php b/src/classes/jpgraph/imgdata_bevels.inc.php new file mode 100644 index 0000000..c98fa57 --- /dev/null +++ b/src/classes/jpgraph/imgdata_bevels.inc.php @@ -0,0 +1,104 @@ + 'imgdata'); + + protected $colors = array('green','purple','orange','red','yellow'); + protected $index = array('green'=>1,'purple'=>4,'orange'=>2,'red'=>0,'yellow'=>3); + protected $maxidx = 4 ; + + protected $imgdata ; + + function __construct() { + //========================================================== + // File: bullets_balls_red_013.png + //========================================================== + $this->imgdata[0][0]= 337 ; + $this->imgdata[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. + 'BMVEX////////27t/f3+LFwcmNxMuxm62DmqKth1VpZmIWg6fv'. + 'HCa7K0BwMEytCjFnIyUlEBg9vhQvAAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. + 'RQfTAxcBNhk+pYJVAAAAl0lEQVR4nE2Q2xLDIAgFHUWBKJf//9'. + 'oekmbafVDZARRbK/pYTKP9WNcNv64zzUdd9BjmrgnsVXRNSzO3'. + 'CJ5ahdhy0XKQkxld1kxb45j7dp0x2lBNOyVgQpMaoadX7Hs7zr'. + 'P1yKj47DKBnKaBKiSAkNss7O6PkMx6kIgYXISQJpcZCqdY6KR+'. + 'J1PkS5Xob/h7MNz8x6D3fz5DKQjpkZOBYAAAAABJRU5ErkJggg'. + '==' ; + + //========================================================== + // File: bullets_balls_green_013.png + //========================================================== + $this->imgdata[1][0]= 344 ; + $this->imgdata[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. + 'BMVEX////////27t/e3+K3vriUub/Dm18j4xc3ob10k0ItqQlU'. + 'e5JBmwpxY1ENaKBgUh0iHgwsSre9AAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. + 'RQfTAxcBNTfJXtxZAAAAnklEQVR4nE2QWY4EMQhDUVhSIRC4/2'. + 'kbaqLp9p+f2AxAayAzDfiK9znPORuvH0x8Ss9z6I9sHp6tcxE9'. + 'nLmWmebmt5F5p2AR0+C9AWpLBjXRaZsCAT3SqklVp0YkAWaGtd'. + 'c5Z41/STYpPzW7BjyiRrwkVmQto/Cw9tNEMvsgcekyCyFPboIu'. + 'IsuXiKffYB4NK4r/h6d4g9HPPwCR7i8+GscIiiaonUAAAAAASU'. + 'VORK5CYII=' ; + + //========================================================== + // File: bullets_balls_oy_035.png + //========================================================== + $this->imgdata[2][0]= 341 ; + $this->imgdata[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. + 'BMVEX////////27t/f3+K5tbqNwcjnkjXjbxR2i5anfEoNkbis'. + 'PBxpU0sZbZejKgdqIRIlERIwYtkYAAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. + 'RQfTAxcBNgK0wEu5AAAAm0lEQVR4nE3QVxIEIQgEUErAgTHA/U'. + '+7zbipf9RXgoGo0liMmX6RdSPLPtZM9F4LuuSIaZtZWffiU6Iz'. + 'Y8SOMF0NogBj30ioGRGLZgiPvce1TbIRz6oBQEbOFGK0rIoxrn'. + '5hDomMA1cfGRCaRVhjS3gkzheM+4HtnlkXcvdZhWG4qZawewe6'. + '9Jnz/TKLB/ML6HUepn//QczazuwFO/0Ivpolhi4AAAAASUVORK'. + '5CYII=' ; + + //========================================================== + // File: bullets_balls_oy_036.png + //========================================================== + $this->imgdata[3][0]= 340 ; + $this->imgdata[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. + 'BMVEX////////27t/e3+LO3hfYzz65ubiNwci6uQ12ipadgVGa'. + 'fwsNkbhnVkcaZ5dwSA8lFg7CEepmAAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElN'. + 'RQfTAxcCBySi1nevAAAAjElEQVR4nFXPWw7EIAgFUNMoCMhj/6'. + 'staKczc/2RkwjS2glQ+w3YytgXCXCZpRo8gJdGxZadJws13CUP'. + '4SZI4MYiUxypeiGGw1XShVBTNN9kLXP2GRrZPFvKgd7z/sqGGV'. + '7C7r7r3l09alYN3iA8Yn+ImdVrNoEeSRqJPAaHfhZzLYwXstdZ'. + 'rP3n2bvdAI4INwtihiwAAAAASUVORK5CYII=' ; + + //========================================================== + // File: bullets_balls_pp_019.png + //========================================================== + $this->imgdata[4][0]= 334 ; + $this->imgdata[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. + 'BMVEX////+/v7i4eO/w8eHxcvKroNVormtfkjrMN2BeXQrepPc'. + 'Esy4IL+OFaR7F25LHF8mFRh5XXtUAAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. + 'RQfTAxcBNgkjEpIxAAAAlElEQVR4nE2QAQ7FIAhDDTAVndL7n3'. + 'ZV/7JfEwMvFIWUlkTMVNInbVv5ZeJqG7Smh2QTBwJBpsdizAZP'. + '5NyW0awhK8kYodnZxS6ECvPRp2sI+y7PBv1mN02KH7h77QCJ8D'. + '4VvY5NUgEmCwj6ZMzHtJRgRSXwC1gfcqJJH0GBnSnK1kUQ72DY'. + 'CPBv+MCS/e0jib77eQAJxwiEWm7hFwAAAABJRU5ErkJggg==' ; + + } +} + + +?> diff --git a/src/classes/jpgraph/imgdata_diamonds.inc.php b/src/classes/jpgraph/imgdata_diamonds.inc.php new file mode 100644 index 0000000..a0d6a42 --- /dev/null +++ b/src/classes/jpgraph/imgdata_diamonds.inc.php @@ -0,0 +1,177 @@ +'imgdata'); + protected $colors = array('lightblue','darkblue','gray', + 'blue','pink','purple','red','yellow'); + protected $index = array('lightblue' =>7,'darkblue'=>2,'gray'=>6, + 'blue'=>4,'pink'=>1,'purple'=>5,'red'=>0,'yellow'=>3); + + protected $maxidx = 7 ; + protected $imgdata ; + + function __construct() { + //========================================================== + // File: diam_red.png + //========================================================== + $this->imgdata[0][0]= 668 ; + $this->imgdata[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA/F'. + 'BMVEX///////+cAAD/AADOAABjAABrAADWGBjOCAj/CAj/GBj/'. + 'EBCcCAiMOTl7KSl7ISFzGBilGBjOEBBrCAjv5+eMQkK1QkKtMT'. + 'GtKSnWKSn/KSlzEBCcEBDexsb/tbXOe3ucWlqcUlKUSkr/e3vn'. + 'a2u9UlL/a2uEMTHeUlLeSkqtOTn/UlL/SkrWOTn/QkL/OTmlIS'. + 'H/MTH/ISH39/f/9/f35+fezs7/5+fvzs7WtbXOra3nvb3/zs7G'. + 'nJzvtbXGlJTepaW9jIy1hITWlJS1e3uta2ulY2P/lJTnhITne3'. + 'vGY2O9Wlr/c3PeY2O1Skr/Y2P/WlreQkLWISGlEBCglEUaAAAA'. + 'AXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAA'. + 'sSAdLdfvwAAAAHdElNRQfTAwsWEw5WI4qnAAABGUlEQVR4nHXQ'. + '1XLDMBAFUKUCM1NiO8zcpIxpp8z0//9SWY7b2LHv6EU6s1qtAN'. + 'iMBAojLPkigpJvogKC4pxDuQipjanlICXof1RQDkYEF21mKIfg'. + '/GGKtjAmOKt9oSyuCU7OhyiDCQnjowGfRnooCJIkiWJvv8NxnG'. + 'nyNAwFcekvZpPP3mu7Vrp8fOq8DYbTyjdnAvBj7Jbd7nP95urs'. + '+MC2D6unF+Cu0VJULQBAlsOQuueN3Hrp2nGUvqppemBZ0aU7Se'. + 'SXvYZFMKaLJn7MH3btJmZEMEmGSOreqy0SI/4ffo3uiUOYEACy'. + 'OFopmNWlP5uZd9uPWmUoxvK9ilO9NtBo6mS7KkZD0fOJYqgGBU'. + 'S/T7OKCAA9tfsFOicXcbxt29cAAAAASUVORK5CYII=' ; + + //========================================================== + // File: diam_pink.png + //========================================================== + $this->imgdata[1][0]= 262 ; + $this->imgdata[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'. + 'BMVEX///+AgID/M5n/Zpn/zMz/mZn1xELhAAAAAXRSTlMAQObY'. + 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. + 'AHdElNRQfTAwsWEi3tX8qUAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'. + 'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'. + '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'. + 'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'. + '==' ; + + //========================================================== + // File: diam_blue.png + //========================================================== + $this->imgdata[2][0]= 662 ; + $this->imgdata[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA+V'. + 'BMVEX///+AgIAAAJwAAP8AAM4AAGMAAGsQEP8YGHMQEHMYGP8Q'. + 'EKUICJwICM5KSpQxMYQpKXsYGNYQEM4ICGsICP97e85aWpw5OY'. + 'xSUv85ObVCQt4xMa0pKa0hIaUpKf+9vd6EhLVra+dzc/9SUr1r'. + 'a/9aWt5SUt5CQrVaWv9KSv8hIXs5Of8xMf8pKdYhIdYYGKUhIf'. + '/Ozs739//v7/fn5+/v7//n5/fW1ufOzufOzu/W1v+trc69veel'. + 'pc6trd6UlMa9vf+MjL21tfe1tf+UlNZzc61ra6Wlpf+EhOeMjP'. + '9ra8ZSUpyEhP9CQoxKSrVCQv85Od4xMdYQENZnJhlWAAAAAXRS'. + 'TlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAd'. + 'LdfvwAAAAHdElNRQfTAwsWEx3Snct5AAABFklEQVR4nHXR5XbD'. + 'IBgGYM6AuHsaqbvOfeuknev9X8xISbplSd5/8JyXwwcA/I0AKm'. + 'PFchVBdvKNKggKQx2VIoRwMZihMiQE49YUlWBCcPL0hYq4ITh+'. + 'qKECUoLDZWqoQNA766F/mJHlHXblPJJNiyURhM5eU9cNw5BlmS'. + 'IrLOLxhzfotF7vwO2j3ez2ap/TmW4AIM7DoN9+tu+vLk6Pdg9O'. + '6ufXjfXLm6pxPACSJIpRFAa+/26DhuK6qjbiON40k0N3skjOvm'. + 'NijBmchF5mi+1jhQqDmWyIzPp1hUlrv8On5l+6mMm1tigFNyrt'. + '5R97g+FKKyGKkTNKesXPJTZXOFIrUoKiypcTQVHjK4g8H2dWEQ'. + 'B8bvUDLSQXSr41rmEAAAAASUVORK5CYII=' ; + + //========================================================== + // File: diam_yellow.png + //========================================================== + $this->imgdata[3][0]= 262 ; + $this->imgdata[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'. + 'BMVEX///+AgIBmMwCZZgD/zADMmQD/QLMZAAAAAXRSTlMAQObY'. + 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. + 'AHdElNRQfTAwsWEwcv/zIDAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'. + 'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'. + '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'. + 'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'. + '==' ; + + //========================================================== + // File: diam_lightblue.png + //========================================================== + $this->imgdata[4][0]= 671 ; + $this->imgdata[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA/1'. + 'BMVEX///+AgIAAnP8A//8Azv8AY/8Aa/8I//8Y1v8Izv8Y//8Q'. + '//8InP8Qzv8Ypf85jP8he/8Yc/8Ia/8pe/8p//8p1v9Ctf8xrf'. + '8prf8QnP8Qc/9CjP+1//97//9r//9S//9K//9C//85//8x//8h'. + '//9r5/9K3v9S3v851v97zv9Svf85rf8hpf/G3v9SnP9anP9KlP'. + '8xhP/n7//v7+f3///n///O//+U//9z//9j//9a//975/9C3v8h'. + '1v+E5/+17/9j3v/O7//n9/+95/+l3v9jxv+U1v8Qpf9avf9Ktf'. + '+Uxv+11v97tf9rrf+cxv+Mvf9jpf+tzv+Etf/O3v/39/8Akkxr'. + 'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACx'. + 'IAAAsSAdLdfvwAAAAHdElNRQfTAwsWEiHk6Ya/AAABGUlEQVR4'. + 'nHXQ13KDMBAF0J2o0E01GHDvJa7p3em95/+/JQJMYjDc0Yt0Zr'. + 'VaAaxHgtxwbSGPkGQpOIeQ2ORxJiJmNWYZyAhZR0WcgQGhViU0'. + 'nEGoedDHGxgRapRPcRpXhOr7XZzCmLjaXk9IIjvkOEmSRLG62+'. + 'F5XlEElhA5sW21GvXj6mGlDBfnJ51lr9svnvEKwH1hu2QPbwd3'. + 'N9eXVzuL7/Hn29frdKaamgcgy67L3HFG9gDefV+dm5qme4YRXL'. + 'oVR374mRqUELZYosf84XAxISFRQuMh4rrH8YxGSP6HX6H97NNQ'. + 'KEAaR08qCeuSnx2a8zIPWqUowtKHSRK91rAw0elmVYQFVc8mhq'. + '7p5RD7Ps3IIwA9sfsFxFUX6eZ4Zh4AAAAASUVORK5CYII=' ; + + //========================================================== + // File: diam_purple.png + //========================================================== + $this->imgdata[5][0]= 657 ; + $this->imgdata[5][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA/F'. + 'BMVEX///////8xAP/OAP+cAP9jAP9rAP+cCP85CP/OEP9SKf/O'. + 'CP9CEP9zGP9rCP+lGP/WOf/WIf9KIf9jOf+MQv+EMf97If9zEP'. + '+1Sv+lIf/ne//eUv/na//n5//Oxv/Wzv+chP9zUv97Wv9rQv9a'. + 'Mf9KGP/v5/+te/97Kf+9Y/+tOf+tKf+lEP/vtf/WMf/WKf/v7+'. + 'f39/+tnP+9rf9rSv9jQv9CGP+ljP+EY//Gtf+tlP+Ma/9zSv/e'. + 'zv+UUv+9lP+cWv+lY/+cUv+MOf+EKf+UQv/Opf/OhP/Ga/+1Qv'. + '/Oe/+9Uv/ntf/eWv/eSv/WGP/3zv/vlP/WEP//9/+pL4oHAAAA'. + 'AXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAA'. + 'sSAdLdfvwAAAAHdElNRQfTAwsWEjX+M1LCAAABDklEQVR4nHXQ'. + '1bLDIBAGYFqIEW+ksbr7cXd3ff93OUCamdOE/Mxw882yywLwPz'. + '+gNKotlRFUVnNUQlCxTMRFCKEdE+MgpJaEiIOU4DKaoSIygtb3'. + 'FBUQrm3xjPK4JvXjK0A5hFniYSBtIilQVYUm+X0KTVNiYah+2q'. + 'ulFb8nUbSovD2+TCavwXQWmnMA6ro+di+uR5cPzfPhVqPV3N1p'. + 'n3b3+rimAWAYhP3xnXd7P6oc9vadPsa1wYEs00dFQRAFehlX21'. + '25Sg9NOgwF5jeNTjVL9om0TjDc1lmeCKZ17nFPzhPtSRt6J06R'. + 'WKUoeG3MoXRa/wjLHGLodwZcotPqjsYngnWslRBZH91hWTbpD2'. + 'EdF1ECWW1SAAAAAElFTkSuQmCC' ; + + //========================================================== + // File: diam_gray.png + //========================================================== + $this->imgdata[6][0]= 262 ; + $this->imgdata[6][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'. + 'BMVEX//////wAzMzNmZmbMzMyZmZlq4Qo5AAAAAXRSTlMAQObY'. + 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. + 'AHdElNRQfTAwsWExZFTxLxAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'. + 'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'. + '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'. + 'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'. + '==' ; + + //========================================================== + // File: diam_blgr.png + //========================================================== + $this->imgdata[7][0]= 262 ; + $this->imgdata[7][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'. + 'BMVEX///+AgIBmzP9m///M//+Z//8hMmBVAAAAAXRSTlMAQObY'. + 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. + 'AHdElNRQfTAwsWEwCxm6egAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'. + 'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'. + '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'. + 'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'. + '==' ; + } +} + +?> diff --git a/src/classes/jpgraph/imgdata_pushpins.inc.php b/src/classes/jpgraph/imgdata_pushpins.inc.php new file mode 100644 index 0000000..e59b742 --- /dev/null +++ b/src/classes/jpgraph/imgdata_pushpins.inc.php @@ -0,0 +1,517 @@ + 'imgdata_small', + MARK_IMG_SPUSHPIN => 'imgdata_small', + MARK_IMG_LPUSHPIN => 'imgdata_large'); + + protected $colors = array('blue','green','orange','pink','red'); + protected $index = array('red' => 0, 'orange' => 1, 'pink' => 2, 'blue' => 3, 'green' => 4 ) ; + protected $maxidx = 4 ; + protected $imgdata_large, $imgdata_small ; + + function __construct() { + + // The anchor should be where the needle "hits" the paper + // (bottom left corner) + $this->anchor_x = 0; + $this->anchor_y = 1; + + //========================================================== + // File: ppl_red.png + //========================================================== + $this->imgdata_large[0][0]= 2490 ; + $this->imgdata_large[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMKBh4Ryh89CgAACUdJREFUeJy9mNtTFFcexz+/7p'. + '4Lw1wZJKDGCAwmDAqUySamcCq1ed6k9mn3UfMP7F+1T3nYqn2J'. + 'lZdoDEjpbq0KG8EBFBFBEJye6Zmenkv32Ydu5GYiUMmeqq6uqT'. + '6Xz3zP73aOcIKmAQkIFyD3N/jrBPwlKjLQEglVlJKyUjR3u7cc'. + 'WLoP3/4dvv03LNrQ8I6x1rFbDML9kOmHvh7IRHU9JKmUSG8vpF'. + 'IoXX/TV0AiEM5A5jT0noFMFMJHXUt/d5f9TUAbhtQ3cPFruDog'. + '8klHMnmO0dGYe/myOJGINEwTz3F2higFXgy8PpAkOC+h8hoaCt'. + '4ppHFcQAWSgOQlyI/p+lUjmRxWAwNJd3xca/f34yoFi4tgmjtD'. + 'NIFkJ4xcgBCgVqEBFJ9DqcZea/gNAAVEg7AOGYnHe9XoaJd3+X'. + 'LISSSwnz6lsbKCZ9sHh4UVdBkwdA6cPwNnIfJPmC3Ctgft3wwQ'. + 'QPkvTZJJnbExzfvsM2nMzVG7e5fG48d4lnXwTwEYCjJxuHQBog'. + 'BHUfKkgAIIhiGk06hTp/Dm5qS1uYlXLvtWd4gPgIiCrAEcVckT'. + 'Ab5p7TaYJrK1hQaEenrwSiVfQdc91P0kSp7Ii89D5ksY/kAkLy'. + 'IZXFdXkQjS1YUSEbdcRu168V6+HTUNIKJDRwdE+sBIQmP9Ld59'. + 'bEBA3of4F/D+uXb7rGaaCSmXI3pPj64PDaHCYfEqFVSjgWo2D2'. + '73XlJNQTgCyQykIuBWoNKEeh1aLXBPBCggGdBOgxZVSjoajVhH'. + 'o5HWlIpq4bCQSgm9vXhK4ZZKh5SUYygp4J1EQVUD9xlU18BJQD'. + 'bUbJ5T5XJStyxN9fSI099P3baxV1dRloW2h2ivx/yakg2ot6F1'. + 'EkCa4G1D+zVEq5ArKTWM42Q6HUczQV7U66w9e0ZpdRXlOIQ5vF'. + 'VHUXILKify4jiEzkOqC3peQMoBQymFlMt4Dx6wUSxSsm2UZXEK'. + 'P30QvOUt8/2Sd78CdWwFDTA+gsw3cOlPcPUD+CQB52oQ21RKXM'. + 'eRhGXhOg7VoKrx8KuS4ygZhVg3ZI8FGIfwR9BVgAtfwxdXdP3L'. + '86nUR91dXelNXTeWWy10paQHX602YAP1ADASAL7LJvFtMpOCc0'. + 'cG3FHuGlz6Gr4YEpnoTCbzsdHRbOzy5RCRiLRMk5rjyOtAimwA'. + 'U4U3SurBN/0wnAASBCVDIKpB4kiAB5Ub0/UvO9LpPAMDGfn005'. + 'AxPCzxep3Q6iqPLUseBoufCZRsAE6g5g5kKIDfKUj3wnpAG8QB'. + '/Z1OIqANQuI65AtwNScyYXR2XlAXL2YZHzcklRKWl5GVFXFtGx'. + 'MoAiV/EQaAGH6BUQNWgQpwFngv+Ca8KUAQEBcwgTJHyMV7679R'. + 'XS8YqdSI6u/PMD5ukMtJY3GR2uQkr5aXeWVZOEALmA8WsIAxfL'. + 'd0goVLAdCOd+/YpgqeVtBv4yiA++q/RKKXixe7GB8PSyoljcVF'. + 'yg8fyubyMpulEk2lyAIfAAvAC+B+oOQFoAt/+0rAejB/EzjNri'. + 'vvqNnCd64jxcE39V8spnP+vMbAgDSePKE2NcXm06dslMuUlcID'. + 'TuFvqwXMBU8N39bGgRR+ki0Dz4L5DSAe9NGD7zq+6kcN1L6H2b'. + 'ao5WWaQHllRTafPmWrVMJUimoAQrBYJFjQwre7B6A8YAi8LCgD'. + '5DVo6/hbb/iHK1KggvFeD3hHziQKEMuiNTNDbXGRTdtmw7Iwla'. + 'KGH0oqwbscLOoG46rAY6AOzRhY74PT6QuUKEN4PegXxd/yEDTT'. + 'YMWOk+oEaLkuFdNk0zTZwjfkavDUArXWgGXgFb4dEShXhfYqlI'. + 'ow3w9rg3B6ED60IOOA5oEYQBrcpG+mj9bg0VG8GMJhVDZLyzAo'. + 'VSq8rFYxXXefcjVgG9+uisDrXUCApoKSBcUHMBmHhfcgNwhtD3'. + 'q9IG6Lr15b4OUTmPwBJt8JqGuapp05o0mhoHnptLQfPsR+8IBK'. + 'uYyNH3yr+B77LHheA3tK1Ta+IrMeTL2C6Xl48TOsNWDDgAz7s5'. + '/r+krP/eddCsbj8fDQ4GBm9MqVvvRXX2VULBayRGRzaYn1SoWa'. + 'UjgB4PIB5QK4ZgBXBKaAHxQsrED1H7CRgCUPwgHZDqACmhWwXv'. + '2aDRqGYeRyufS169cvThQKV88PDuYbW1vJ5VRK+5euqxWlPMdX'. + 'SRqgreHbZGN3ijfKBXBTAeh2Fdwi2MofshP/dvKwCmKhp4m83Y'. + 'vj8Xg4l8tlCoXC0MTExMTFkZE/1m37wvLGRvKRacoD1209E7Fc'. + 'pZwYREOQqEJ4z3HskHLsz4AoXykPIBSN0t3dTTQafROoHdumXC'. + '4fjoMiog0ODiauX7+eLxQKV3O53ETdti88nJnJ3rl505ifmWm3'. + 'arWSodR8GNbycDoNHy5C5jFold1k8d+DyvELNwg93d18/vnn9P'. + 'X1oes6nufx/Plz7t+/fxhQKSWJRCI5NjaWHxkZKdj1+sjSwkJm'. + '+uZN/dZ337VqCwullGUVdZjsgIUC5LqhrUPvCugWuApeApPAzY'. + 'PKHWyaphGNRunt7WVwcBARwfM8Ojo6sCzrMKBhGLphGFEF2Wq1'. + '2jc7M5OZ/vHH0MPbt93awkJJmeZsC6ZaMK3DCwvWdNioQUb5B6'. + 'AdBR+9SzkAz/NwHIeXL18iIui6TjgcJplMMjY2th8wHo+Hh4aG'. + 'MsPDw6fddru7+Phxx51bt/RbN260qwsLpZhlFZsw9QJ+2Pbrga'. + 'oJG2FY2oKwuTtVEz9uV34NbqdtbW0xPT1NNBoF4MyZM1y5coWu'. + 'rq5dQBHRcrlc4tq1a/l8Pj9RMs38ndu3Ez//9JNXLRZNyuXZJk'. + 'xVYKoExQpsK/+IaAuYb7no8zjC/R+A4zisrq7u+53NZjl16tQ+'. + 'QIlEIslsNpuPRCJXZ2dnh2/duNFRW1oy07a96MKd575yxRqU1B'. + '5vPMpF5HHa1tYW9+7do7Ozc/eQpZTSQ6FQt1Lq8pMnT/5w7969'. + 'nuLcXE1rNufO9fRMhlKpOyvt9qPtVmvb25fFfvvWbrepVCqHwo'. + 'xaX19vff/996ZhGC8qlkW9Wt1Onz073fXxxz+6MB+9e9dUjuO+'. + '7ebq9wLdB9hoNCrr6+s/4wf3FCJW3fPmTZhXsNWCprjuW66Dfr'. + '928KAfBhJAEgiJSLuzs7OSTqctoFkqlZRt26j/I+L/AGjPTN4d'. + 'Nqn4AAAAAElFTkSuQmCC' ; + + //========================================================== + // File: ppl_orange.png + //========================================================== + $this->imgdata_large[1][0]= 2753 ; + $this->imgdata_large[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMLFQ0VCkHCzQAACk5JREFUeJytmGtzG0d2hp8zNw'. + 'AEcRdJ6EJK9FL0CqZUm9jWbkwq3vhDstl8dmLvz8rP2H8Q75ZT'. + 'pkRfpLgqsS6WIFEKGYkiSBCDO+banQ8DUpRWEkklXQUUqlCDfv'. + 'rp857pgfAOQ4AMOJdg4R/hX96Hf06bvDc5iT07i8yeg8ksiIAI'. + '4TBi/ds9/vivD/njapNHvRBfHXMu410AM+BUoVSF05NQsi1sO4'. + '8402AXwLQTuP31OAZO2aG0MEn14iSlnI1z3LnMk8IZYJyBwjIs'. + '/TWsVIWPJkvMFS4zMfMhUp5BsoCpAAEBLYKaMFGn00jBxnvu02'. + '35+JHmSJEnBpQEcPo38MmCxd/nS9Ry71Ga/g1W9a8gn0GsHkgA'. + '6DGjxkqb5CoO+YxF3A3p+jGjQUzoK+L/V0ADzFMwtSR8eLbAr8'. + 'uXOTf9NzhTc0geSLUQcYHgYEH786RMg0zWJHV2Aitv4x/HpHVS'. + 'QA2YBqTTGIUq5qkPMWaWkVwPnPtAA/BevmZcjxaaUtHh8pJJGu'. + 'DpCB9FvT7A7YT7S3p5vFMNzmWo/O0MSx/Ms3TqI8r59zFTfUQe'. + 'I7SBODE3tnfoIxYnNHligwik0zAzDdVpyKbA8sff5YAeMEwgkV'. + 'cufQeTJzZoCsaFLKXPTnNpoUTNsSgJmNoGsuNQjIDwYD2HlnZy'. + 'k++yxTKXZfKTU8zOpjhneeQYkorSmGERtIlICBKRbLX+y98YN3'. + 'ADcNIm+bJD4U3pPnmbEaRgYVRTGBkDSSsmxKfY7ZLuDJA4hdjl'. + 'JEgyBB2SJOvQ9RzTpNKoEwNq0CNFvOXR3/HxMgYVPObaz8kPmh'. + 'hkEWMatAfRONGGvLizyOE9P8KkpwhPDAgQKJQbELUD0oOIhbbH'. + 'JeVTmowxjAgZutB5AoOngA+2DdYrcTyOyYZP9+QpBvI29vwEhb'. + 'It042BVQgDy9KTMfkwQG1A9ACCLlgBBGUwxxoc52WDh2ATyEPp'. + '1hoaPvrEBh0Dq5an9OUsl/9hylk5b5c+mowLc4E2Jtw4Eoljyf'. + 'ogA/AGEAagNRjGyUxOmEycyVA5EWDBxrmUp3ytLIv/NJP69Goh'. + '+9mFydIvS5PZYkvH1oY/RFtKymlwBFQAgQd+kAA6qSQ8pvn2mp'. + 'SkJkuVFHPHBnQMrEt5Sl+e4/Lvp51PF1PF5Xy6WMvOWZXMom8z'. + 'OZTQ8+j5sbQiMEwopsCIwRtBGIJSCdzbTGo9NimkDcgdC7Bg49'. + 'TG5n4/nfr0Si77WdYp1YzyZEkWPdteaEnB7pPqBTxuIf/VgciE'. + 'SgasCPwh+GNIkaNNag1RiPge5pEhMQVjfoLcF+eoXSvbKxedwn'. + 'LKzC3KWbOi5/sW5a44/SHFUSgVA7SCzRG0AvA9mPOgFIETgu4n'. + 'Ww0wNQWFAqRSL6D2ZQYBdDrQ7R7jXiwgRcvIL02makuTmWtpM/'. + '+BlLMl5vuWzLVEuwH6oYnR1KS8kJINGXMM2YdfRlALoQoQQKeb'. + 'bDVwoMdxQMaLCwLo96HZTF5HbrEhmOftianfZisfzueKv7ZmrX'. + 'MsjhxKXZGBjzyeEHmSE3oWiggtyVGmE8DTIXTC5NxgAxOAGUM8'. + 'fun9mnSSLQ/CxNzOTgJ3LIMgoGwkKBiiMyaVviHVkdCO4FEKNv'. + 'LQzWBYHfITPa4UBVM0LR/WB7ARJsdDDTjA6deYFIFUOimJ3d0E'. + 'sNdLavYYgBpthqKcjiiJRO8K6CK0CsJTjfQAGaJtD9vQFAxNNQ'. + '1FB0yBAfA8gdMAIagLoCVAen0M00zMOTYShNDtoHs9CAIUoI4E'. + '1IBihCdNhsMhsj6NuV7BCC2IBpBqQaaFOENCCeiEsO1BO4RQgy'. + 'I5Hm4k4oIU9MrgZSAdBeTabZz+ODxKQRRBFBJo6IUc51anYRQo'. + 'dto+24FNxYCiaWKkQsj00KkO4gxRRkAngJ868M0u3OkkM+hxQA'. + 'cQ7YD7GO5XYSsPZybh/TCkFIYY+kWniTW4Q7jXgHvHMhiRpmuW'. + 'ca08GZkkZ/nY6TZMNhCnf2CuPoDVJvxpB+q9BHA8Ag1uH+oP4c'. + 'YEPCzDwmzSLquShHW/E0YRbG/BjZtw40hAy7aNzJlzRn75E6N0'. + 'qiwTzafI7kOU3gWrhzZC2iHcbsPqLlxvJnCt4KC1RYAL3I5hzY'. + 'Xv/huePYCtITQMKEnyB4KQvMURuJvw889HGSwUCs7CwkLpo6tX'. + 'Ty/+7nel6VLGDn/8N9m+eZuo1UP8iNhLau6b3RfmOsHBGTUYw9'. + 'WBNeDrGB4+h/4qNLKwTnLbHj9CJw/6GoIh9Jpvq0HHcayFhYXi'. + 'l3/4w9LK8vLKexfma3G/mb/3n1njTivS7tNQaaU1grQDjJ868D'. + 'Axx6vmxnBrY9C9IcSbSXbavNjb/S3eN6/0m1JcKBScixcvllZW'. + 'Vi6uLC8v12q1v/M8b/HxVjP//YYr32yE4dYWvShO0ogi14xwxq'. + 'F4rbnxZ3cMjtpvEEeMvwA0TdOYn5/PffHFF7Vr166tvPeLXyx7'. + 'nrd4+/btyg/frFo//Xgncnd67qCn78earQqcmYD3fSi1wPCTSV'. + '3gzqvm9uFOMl5nUAqFQn5paal26dKla57vf7D+6FHph9VV88af'. + 'vgq79bo70e3VT2l9A3hYg4UiRALVHTCHSZvYBm4A//6quf8zoG'. + '3bpuM4acMwKr1+//SDe/dK31+/bv90/Xrcq9fduNW6rbVeC+E7'. + 'gWdD2DKg4UEpBmPcm10RuScida31ntb62HAigoigDw6Gh0axWH'. + 'QWFhZKi4uLZ+I4PrVer2e+u37dXPvqq6hbr7tOp1NXWq89h6/b'. + '8FBB34WGBesdcPrj38lkMkGlUuml0+mu53nR3t4eo9HoSLhMJk'. + 'OlUiGdTuN5Hq7rvgA0TdO4cOFC7vPPP6/VarXldqdTu7m2lrv7'. + '7beq++BBO263b/tKrfWSXlbvwJ6CuAtDgTYiaBFMw6BSqfDxxx'. + '+rarWqGo0GN2/eZGtrC6XenAkRoVKpcPXqVWZmZmg0Gty6desF'. + 'oIhIOp3Ol8vlmmVZK3fv3Lm09uc/Zwbr653ccPgoNIzvnmn99Z'. + '7W9QG46lAaM5mM2l95GIYUi0VOnz7N7OwsWmsymQzyuse5Q8Mw'. + 'DNLpNDMzM5w/f/7A6AGgUkoajYa9urpayOXzUz/fvZutr68Pim'. + 'F4/2y1+n2o9Q/ru7uPesPhXnyo4A+vfHp6mmazybNnz9jZ2UFr'. + 'TbPZJAhe+8/aS0Mphed5NBoNABqNBqPR6MWBVWstvu/nnj9/Pv'. + 'vo0aPq5uZmPBgM/qcwPf39xV/9ajU1M3Nvq9PZaw8GoT50PjdN'. + 'k6mpKa5cucL58+eJ45j19XWePHnCzs4OnudhmiaWZRGGIVH05r'. + 'yEYYjrumxubrKxsfFyDQJ6NBp1Pc+7C4jWumBaVm+kVL2l1H2l'. + '1G6otS+H6V6z8u3tbVzXpdFooJRicXGRqakptre3uXXr1ltrcT'. + 'Qa8ezZszemWAE9rfUdYBOwtVLRbrPZ+48ff+wDvuu6Sr3MB4Dr'. + 'uty6desgfa1WC3iRyrNnz4pSSmezWUzTfGtYtNYcdvC/9sMlgP'. + 'n5N4cAAAAASUVORK5CYII=' ; + + //========================================================== + // File: ppl_pink.png + //========================================================== + $this->imgdata_large[2][0]= 2779 ; + $this->imgdata_large[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMLFQolY9lkpgAACmhJREFUeJy9mOtzFNl5h5+3b9'. + 'Mz0kzPBWmEVtIiWYhIiC0HCDhB8lb8ISk7nzdZ5+/zJ/8BTmpT'. + '660CZLwG1pVFgBkgGIHECEaa+/T9nHzQCCQuRpCNz6mp6g893U'. + '8/c37ve3qEjxiC4OA4n/Lp/EUu/tsMM/+aEWduVBx7WhdkShcY'. + 'xUH2zo0Dwod/5N6vf8V//PoGdx8M8EOFPtK9jI8BdHCcMuVSmf'. + 'LxHLmSZdm2U8xIbmKETDGDZZnIy4dBbCynyGhphurEDBOlHFnn'. + 'qPcyPxTOwDCOccw7w5nlBRZWylI+ny/mZ6rL1dzUZ5/IWGZU3D'. + 'ZIOMQDDaJcHDVGWUbJBi9odVr0QoVSPzigIEaZ8vgSS/8wZU3/'. + 'k1fylipz5dLM2WlrZqHKaGCKbEbontq3KAKWQyZfZKTgYqc9Bp'. + '2I2PcJ4ogk/UEBQcwipbFZmT13vDBx8fhnE1Ofnp9yJopFyT3X'. + 'yANfks0QHSQMDaL37pOxMLIu2UyVkjVKLjyKSeuD8dAYCFkso1'. + 'gYMaeWJ40T56cl8yAi/O4FSa2P6kYczIDsgVpAqcDImZPMuAB1'. + 'dkLQtcc8a/bwox8IUHAxZVxGZMouSLVYwKuMkD5IxN+JSdsRJB'. + 'pexuTVgYYM6EoGmxkmg3/hEhNUMr/hd7dqbOzExMn/GRDAxWZc'. + 'j3I8HiXfMjF2FQowKw7pjoN6E/Llw/GBJj8qxVOMlX4ipxc/lY'. + 'kl2zBLkmrTcEzMkoNoRLVidLi/9g+Z3I+1xRHX5EcAihxnbPRv'. + 'OTU9kZSmpKPy9FTGrLimPZ1H+UiyGaF67w6n7E1DwMngFDxGvc'. + 'w70v0xZUby5IxjlIyMssUJrJwVWkXBdbXvSvwEibcSdKCAFI16'. + '4/sc0SRo9cGAGq1DwvQFzV6DVuBiV4zYnlEts6A2TSPcSiXoxo'. + 'QqJCEEFMbQ2b69o5qMiOOPqIMQkagu/aSL7waE8101WFShLjk9'. + 'yxgEvjRUiyYd+gwAjY2J9VpXfZ/JEXLhDp3OR6U4T97+hEnPwx'. + 'tv4HsRjy2tTQSFzQgDUnwSLBQRI+x1ZgcH87Vcv4SF19Kt0ezS'. + '1h9s0Ma25pgr/YJfnLnEysok0+ezjM6EBLldGqKIJYuDRhOQEJ'. + 'Oih8X9Q0xmcXNjlCofBJgn78wxVz7L2YWf8tPPz1hnfjbjzfxN'. + 'qVwutq2etZXUQSXikcXGIgUiUkJSDIQMJgYGJsaB3c7b1qQ4GZ'. + 'xSkdGZIwMeNLfK6uezMnvJK3pLxeVixfvMsyVjSNSO6IV9adPG'. + 'AArkEEz8oUkFmBjYGO80qfd6pCWIayD59wIKcsjcKqufn7JO/S'. + 'xfyi+5c24pey5rZ09mJRNkiDdT/tzbkBr3SYkpMYpgEaIJSYhI'. + 'kSOY1GhilAQk5ntDIojxCZ/kf87Pl85xbuWEnLiUy+cW3NNuJX'. + 'MmY5meKf6mT7wZS+THdOjxlG06tIlIOMZxchSxcFFEGAwAGGME'. + 'jwyZYSnWL3cXWiIUbUI6hO/vxXuFOV84ycmlBWthNeflTjuzTi'. + 'lzJmM5s46Ej0J63/ZoPmoy6PYxtYVNhmfs0mbAND1mmKVMBY1L'. + 'mxA1LN7WgXQbCApNhKJHRIM+DQbv7yQGhjnJ5NgFuXBuxpu5mD'. + 'udm3LPuY7pmZLUE6L1SIJaIPFuDAqyw9lnwDYv6NFHkWJh4ZDB'. + 'wCBFD3uMxsTAwcBAiElpE/KcPg36dIiOvpsRxDCyhmlP2YY9ZU'. + 'v8NMb/1id+FGO0DTztkSXLOONUqeITsMkW2zwnJEIDFhYGx+A1'. + 'kwK4mASkvKDPc3p0iYhRRwYUhZLUTyV6Eu0t4s1Y4kcx6W6KaM'. + 'EZThcXH59RRhGEgIAddnBwNEBKqqpUtWBIF22YDIhJsbEkJqFN'. + 'qLtERHs7GnUkwISEQAf0uj30bY39PzbiC6qrDu2cExJ69Nhhhz'. + '59UlIUipCQOnVi4sjG7ubJBy6um0C+he/0iDHQKIQERYyKFLqr'. + 'SI/W6kJCnvOcrWSLSquC1/Jw9Ks3R0FQKHr0uMc9bnCDGjX69A'. + 'H0XlcJkibN5jOe/alCZStHbjJL9lSMLkXExvCXRiDV6GZEeGeX'. + '3TvvBVQoEjfBL/v0rT75Th7VU5C8gktI6NLlMY+5yU3WWGODDf'. + 'r098tHpNFNH7/2lKdXXdz7efLzVaqJIBOCmK8AJUlI6g0aV+9y'. + '9+p7AR3bMQpTBWPy7yeN6fy0jNwewfpvC9Xe+3kFoUuXe9zj5n'. + 'BusEGHjh6GIAGawC2FWuvSvbbF1maFylZAsC1ISZADBiVNSJrP'. + 'eX73MY//skHP85z5+fnSxQsXj//4n39cmnPn7LbZlsajBmEnBL'. + '1nuEGDG9x4aa5Ldz+h0RCuBqwBv1Wo+7vs9r7n++0MmYeAM+zB'. + '+61EK1QUEnbbtN+9Bh3Hsebn54u//PdfLq9eWl2ZnZ1dSnaSwu'. + 'Pin40b9g3doKE0WoNIl65xj3v75njd3BBubQi6ExKmDWkMRKSl'. + 'tSbVKQcMao1Go5Ugb0+x53nOyZMnSysrKydXLq1cWlxa/McgCB'. + 'Yev3hU+GPrD3I5/q94k3pXYQY58q6B5Bs0HB//neaGx00gyWaz'. + 'VCoV7bquCoKAnZ0dfN/f03egLGj0m3XQNE1jdnY2/+WXXy6trq'. + '6uzP3oR5eCIFi4detW5feXL1vr679Let37zVB3/mQytjXJwmSB'. + 'wikHp9ShY0RESqObwPrr5oBERKhUKly4cIFqtUq9XufmzZtsbW'. + '2hXvuDwTTNtxZq8TyvsLy8vLS4uLgahOHphw8elL69fNlc++qr'. + 'uFOrNXPddm1cczVL5f5P+Lv5MuOJgTGxwYbZpZsCdeAq8M1Bcw'. + 'CGYeC6LtVqlRMnTjAyMkKn0yGXyx0N0LZt03Ec1zCMSrfXO37v'. + 'zp3S769csb+/ciXt1mrNdHf3ltZ6Lca8ZpJsduhtCdb2gEFJoQ'. + 'xADYHuHDS3f32lFEEQUK/XGRkZoVAocP78eZaXl9FaI/Jq25Uk'. + 'yWHAYrHozM/PlxYWFibTND32sFbLXrtyxVz76qukXas1M61WTW'. + 'm99gx+20TdN9jqtfjP7QzOwwYNp037Zd0DukDnIByA1pqdnR2+'. + '++472u02Z8+eZWJiAsMwDsEBRNGBzYJpmsaJEyfyX3zxxdLS0t'. + 'KlVqu1dP3q1cLta9ekU6u1dat1J9b6Sk9kraV1rYXegW7apDYw'. + 'kFY6fPc4MNTw88bwfZ/NzU2UUnieRxAEiAiGcXiXfcigiIjruo'. + 'VyubxkWdbK7fX1xWvffFMInjzBM82uMT5+p++6V1UUrSe7u03t'. + '+8lezlKt3gHyl0aSJDQaDa5fv876+vo+w6FzDq1BpZRsb2/bly'. + '9f9vL5/Njdu3fzG0+eMJHNxsfn532vXN5NPG/7abPZal6/Hvfe'. + 'kroPHfsm98f7AHW9Xo+//vrrlmVZm71+37QNw3JnZ9PK4uJGpV'. + 'pt4Dh+vLGhsrmcfv1iHzu01m89HjIdCon2fb8TBMHtvYeRUn50'. + '1Oj4vqp3Ok1f5LYSadfr9dQfDN642P/XeF2DA+SBAuA4jkOhUK'. + 'BQKESO43S11p3BYBDt7u4y+CtB/i/q7jp1GMiw2AAAAABJRU5E'. + 'rkJggg==' ; + + //========================================================== + // File: ppl_blue.png + //========================================================== + $this->imgdata_large[3][0]= 2284 ; + $this->imgdata_large[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMLFRAiTZAL3gAACHlJREFUeJy9mGtv29YZgJ9zKF'. + 'F3y/Q9jh05tuQkarKgbYasde0UBdZgwNou/Vqga/sD9mP2B4a1'. + 'BbZ9atFPxb5sqOtmXbI19bqsluPYiR3HN90vFEWRZx/IJI5zqa'. + 'x0OwBBSgR5Hj7v+55zSEFXTUgIJyA9C6/9RsjMjAyFIxxJCDc7'. + 'iBqKgyZACGg3G2x9+xXf/fG33P3mC9qNKsp1O+1JdkEnQTdgIO'. + 'ttCSMUi8gj072MnugllAyB9G8rBGi6RsToJTF6iuRoFi1kHKZf'. + '7fB8Iggj0/Dy23D2dakNTR3JDsXPvzstxmZGRMER1EwHhQAEgE'. + 'CLhIkPD6InY9S3djGLJVBtQP1Qb4HDAyoJYQOOZkPx49nhTH9i'. + '7MUBGT7egxkJgd70wZS/CUkoZtA/fRoE1DZ2ACiv52ibReCp4e'. + '7CIEHomxDiuVdGTqUnf/ZeOjR8fpiVXZul5ZrY3bWwbdcLr/dA'. + 'AAIpAwQjUWIjQ+g9HZvswiCgBVF9/SI6OSLGzo0i+oLi6+Utbq'. + '+bKEftgwOE/0Ohocf66M+cBjo22U2RQLIHMhmYnvaOpR9S8bSU'. + 'UqCURGpRkuMZMm9cIvPGJZLj0yBjT2LprkiSkykx9cuXIhOnUs'. + 'm+QNC2XdG02ggBTcvFabsPWwTPpBAChSCgh4kYBpoeplWp47Qs'. + '7EYDt21xINzd5GCAxLExRl89Z+nHjpbKMmjbmkgfDzI0JEW53K'. + 'Jaa6NcAOEX8v52uJzsBlAS6u0hcnTIccPRqhWPCUcLD+s1EaUp'. + 'HCEhEMCyHNpt9SjgIU12A6iw6xb123vYhaaKjB9tlgMD5X+uBp'. + 'zdkpg6azA8EaNQtKlVba+Xez4eCntnJrsDdFsW5nYFpxlFN846'. + 'DXe8utkM4mhi+EgQmjYbS2WqexZKk6BpjwJ2YlK5VjeA3pNDiH'. + 'YjRWPzPE7tmBo8EWwGhkXx+z3uXL7D3rU97LIF8RBEAl6lK/Uo'. + '6JNM1rZ2aTcr3eUgIQOGTgbdwXMGyRejenLYTvQGbAdRuetSud'. + 'OivVuFZgtCEgICghICnZoMhmlVTPR49LCAEkQUhk/B7KXe0MWf'. + 'nxj8xVR/cDheK14WZmtVMJSBnlGoN6FmQq0FLfdwJgORKPHRo/'. + 'Snzx4G0F/FjJ4KiOdmjPCrrx8bffnMybMv9MQGNG3rzlVqtR1B'. + 'sh/CYXCD4Aag1oCW7ZnUOjSp6WFi/QNEB8Y7BfTNjZyCmUvJ0I'. + 'XXT47MTp98Ybon9VZCk8cVazfqlNargsY34G7ByAlIjkHd9CCr'. + 'LbBdiHViUgiECuDKYCdz8b2cywREdiYZOj8zNnLuzOTzx6ODp+'. + 'OaGaqwVzBFqz0Idhz2loE7YEwBLaAJLQcKbW8qjAcBF5Jh0AMP'. + 'IOHe6kxgtb3UMO2OxkF//ffK28nQqxfvm3szrtnDVa799Qb/+v'. + 'NtsbNSpm3tAv8B+w7Ub0FhAyoBcMPec9oK6raXk48ziQBXQcmC'. + 'pT3YqHa0mpEBkTR6wz/Jjo2cy04+fzwxdDquNfQKO7sFUbpu0c'. + 'wp3JoAYsA42Bbkl4GCryUNDEM7Avm6Z/CgSYBWG8pNuFuDu1Wo'. + 'tjoxKIJGeHIiM/jmK9NnX5ycuJQMtUcqXPvLDTa+qIie4hAJ1U'. + 'vdrmO2HaDfB931twJgAn1A4lGT96obPHPLBbhVgUoTHHWo9aAA'. + 'JVAKpyKEmQNzWRENAsL18ycKjAFN/9gCNvzLB/390MMmE7pnDi'. + 'Bvwt0K5Jv3O+0oB22nJ1Vvjb/UMhOpcKknqN1OiMB2DNHU2G5s'. + 'sVndpGJVcZXjX1IAlvw9PmhRQcOFPhsSDkiBrQR1G7brgs0a7D'. + 'ag3FK4rguqBXarI4Nt1SJv5gls7TEWtJDRBO2GwnIs8maevFnA'. + 'Gx6awLZvzeTBu4kFbLigijC47pscpx0xyDfkvtUEnlarCDtrUC'. + 't2HGIhvPHVdVwqjTIrxRU2a5uUrYoP0QZ2gMvACl7+3V/LuKDq'. + 'sJuDy597516+CEezIHXv7vcgXQu2l+Bvn8He9Y4AE4kgk5P9DE'. + 'R6aFdq5Et5Nit3yTf3m9sBcsAN3+D98c0Fit5JawE25r1zg1Fo'. + '5B8GFD7g+nVYnu8EUEop9XTa0N/9dUbqcphP/rDJzbUClVbpgR'. + 'y2fXM3fND95qj75J8AC6BWPINfVSBieK+x+6cS5UCzCLu3oFV9'. + 'GqCMx2NGOp2Znpv7aXZudsool3T5J/179sxVlHJ4kGPrP2COBX'. + '/7DmiApWCjxIMXpYNznYuXM+6TAKWUMppOZzLvv//ery5cuDCT'. + 'SqVS336bCwr1JfAPB9r+2KAFwJS+OcETzZHz/7v3etl6ipz77X'. + 'GAMh6PG+l0OjM3NzczOzs3k0pNnFlbW43+e/GKtMqrblSsF03V'. + 'WHcJA0PjIAzvg9JTze2H67g9DjAwOTmZ+uCDD96anZ2dnZiYmF'. + '5dW41++Lvfa1fnr7qllVK9103mXNTnJgPA+YugsvB3HTaEl+Qs'. + 'AZ/yeHPPDCiTyaRx5syZbGoilV1dW00szC9oV+avusuLy0Xd0X'. + 'MgFkDM+zkYBZEHV8f7wwKu84zmngQoNU0LaZoWUa4K31y5qX/8'. + '4cfyyvwVN5/L10NOKNeg8UmDxoKF5Vfj1xXAgD0JrgAcvBDfel'. + 'a4g4AykUgY6XR6emJiIru2ttZXq9S0K19eUcuLy8WQE8o5OAsN'. + 'Ggsmpl+NpoL1g9X4UBU+C9xDgEKIwNTUVOqdd955M9mbnJ3/cj'. + '6Vu5aTheXCQXNdVeMzAwJSCGEA2XKpnF1cXIzlFnOVhJPIKdR+'. + 'c88ctq4AlVKsrKzw0UcfKcC5uXqzXnNqSzb2pwLxOHP/l7Z/BN'. + 'eB01LKt4HTrusKvGr8jB+hGn8MQAkYQMrfw4Nq/MFPtf+rdvDb'. + 'k8QL+/5Z4Uepxm7bfwHuTAVUWpWaqAAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: ppl_green.png + //========================================================== + $this->imgdata_large[4][0]= 2854 ; + $this->imgdata_large[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMLFQ4hANhluwAACrNJREFUeJytmF1zE1eagJ+3u9'. + 'XdkvUty2AbmLEtEzDBgZ0UpDBOalNTUzU3czl7tct/2n+wt3M/'. + 'NVM12SSTQQSyW2TA+QAJQogtYYFtyfrqL3WfvWj5g8AEjzfvhS'. + 'SXjk8//Zz3Pf3qCMcJAWxMKlT4kH+jwu/FknnJSUItKFHzCrKA'. + 'BggBQx5ziz/wn/yBz3hED4/oaJfSjgVoYjJJgTLTZCjohp7IGT'. + 'k5aZ4kb+bRTR30Q7djj8f/kpPMUSCFedRL6W8e8qMQNE6S4xpv'. + 'c5HrTPFubiJ3ZnlyOXV59rJYU5Z00h1c3d0brxAiUkScRijisk'. + '6XLTyiN3s8HuAJpniXa/q8/pt8Or+0kF8oXJm5YiydWcIpOrJu'. + 'rjOQwd54AQwsMpTJYhPSoYuLQ58An/DnBQSdImXO8avsTPbqpc'. + 'lLp67OXDVzMznZLGxSs2qyIRu4at8gKHQEC50kE1icxqCAdxST'. + 'xjEA44tqaJlERl8uLWvvnX5PHuQfcCdxh5qq0aX76vj4WgWyXO'. + 'QiNgBP8IAaddr08X8+wHFmJSQhBbPAZGoSZSt5wQs6qoNC7UEd'. + '4AEoLIQSCaCCy78Dv8Tiv1hjjW1CRj8XIAgEKqDtt9keboMJZa'. + 'vMjuzQVd3Xr9prTJo+GF/jKZea95R25Lxs8jg5qFGiwDnOS0mW'. + 'NE0rjNRIt3WbklUCA9mV3Zdz8OBT/JfCQLB0SKYVVjGFYSfx/E'. + '26ow4e6uDujlPFQpE0FU6P8qNTHdXJdEdda0qf0itWBVM3pa/3'. + 'ccUlIECJet0cAJoeYk5EZCeS5IwEoerSxccJBwRqFFf38QCTaO'. + 'TRVFKJm3NTbtLNSyh2IkhIXsvLCesEGNCWdmwyruSD/z9kUlRc'. + '3bqNlSxhJNJ43p5JITrOEis8Qtr0cXEpU/JT/pmO18n2vb42pU'. + '3JnDnHMBqyPlpnoAaxhr2llv1ZUBqEGlqYwDQMsskMOcMgVL3Y'. + 'ZOQTHAcQQiIGjHCwCaiovjrv4hbcpKuJJjIcDHm685RGr4GLCx'. + 'YHkAcrLoAoDSLBiAQrMkjqybHJCbxgh+7xAC1MpsgzwRwD3qHL'. + 'WyTIBdlAa6u2rHfXaew06PV78ZZjAwleNnkolECoH5i090wOcY'. + '+TgwYzFHiPi1zkOkXexeAMASnVU+LiyiA1wFUuaqggACLizeWw'. + 'ycMzyssmVYKkbpGyC5T+OUALk2mKLHKWf+ED/az+YW42d66YL+'. + 'aNrmEEzQCFEnKw368EgEvcN1m80eTIQIt0TFOjMJHkzNEBBYPp'. + 'sblf8QHzrORO5JaWZ5ZLl6cuJyyxpNPv4PZdoT+GyIxBfI5uUg'. + 'eJMCwP2/bIHO1JEudcgUUWOceKNq99mCvnzs5PzRcuTV4y5mRO'. + 'SMIjo47z5S7a94oQCNKgJsZwO7D/IDNg3/LLhRNXt4JohBb4aG'. + '82GLdXcf93mQ+Y43r2RHZp+cRy6cqJK4l8MS+tdItaqiYtc0Mm'. + 'QpfJARh98HYh9IiXVcaAo58wGb+LBAjbSPgCOcoSa0wzxXtc08'. + '/pv8mfyL+9MLVQvDJ1JVHJV6SZbFI1qtTsB+KlehRtRTGE8Afo'. + 'P4DRcAxiEudhAHjjzz+ubgX4oHowakHQOlqzICQwyVPITGVOXi'. + 'xfLF6aumzmczl5lHzMff2+fCdPaGttEkXoLQAO9B7C6EugPYby'. + 'gVPjGXc5eIbNAJPjGwiAbaAJUQv8wVG7GROkJFpyOqn/ovgLba'. + '44L0+sDaraXb6jzq7aBQWjBOyUoHcaopOgmaA3IRyNDZnA1HjO'. + 'HSBkr7eEFDAEngHrQCf+/s2A8cSiSkqcKUeeTjwFy2Jd78t3+L'. + 'TR4itIiBLwLQhzkJyB5Cx4HXDaENVQCBAQcRqFIHTRaBIvuYXg'. + 'AdsouuNxEL0ZUBHnSQp66R73zYfUtQ6OytKT8RckQAJQoLtgO5'. + 'BJgj0D/WfgdyHaAHx8THoUcbGx8ciwhUl3bDEiToURPooeI7pH'. + 'MziK9Yd9nU5a6GgKjOH41vsgI4hAcyC5AZkapF+AoYNrjjsuhx'. + 'FbtPmeB5ykyQQzTPAWAQWC8S9oAI0QRRuPb9jkmyMZNAOTklvC'. + 'GGYZaFkGmkVAh8h4DtKFMIBunG+pB5B5AIkGBDsQ+qBiL20caj'. + 'zhJknq5KlgMkLjJHJos4kYEbFJi5vc5eYbATVN02bNWe19+32t'. + 'aJWlFm3wbf8Rz5NbDFJdlOFBF/g7cBf0JkrbBb+F6j1DOduEkU'. + '8bWCOiSofPWadBnSZDWmgUkEMGhZCINut8S/0NBtPptFlZrBSu'. + 'vnt1+ndnflfIp9OJ/279Ubbbd+lP7KBKPoEBsgnqLph/BRzwdS'. + 'LnBUFvHcfdpRsGPAGqwMco6jynz+e0SPKYCHMfLX5VKHwcenR+'. + 'Igd1XTcqlUr+xn/cePv91fevzy8sLO2OtrOpWkqL7gXKSAVRdh'. + 'ZFEmEXoYkwBNqovoc/3GHH3aUR+jwC1oD/AWrANi4hGwyBzqEG'. + 'Vvb77Dgi0eT1VZzJZMxKpVJYXV1dXF1dXVm6sPSvruue3Xzcyj'. + '6/syvDzwj0lNazK6Fj5LFCRZouZpBABj6jXouu3+Np6HNvDHaf'. + 'g91t74msbMuOJicnSSaTKKUQEUQEpRSO69But1/dB0VEm5uby9'. + 'y4cWNpdXX1+sLCworrume//PuXpeqnVeOban0U1PW2kcx+O9L7'. + 'Te9sUB4lWFR9SqNtNGcHx+/RDD2+Am4D94CnQA8OjjlEhMnyJC'. + 'srK8zOzu7BiYioMAzZ2Njg9u3brwIqpSSXy2WXl5eXLly4sOo4'. + 'zoV6vV6oflrVP/7Tx8Hmw1Zb6ydqmpWp7ha8h4O3gjOhzVANmF'. + 'XPMNQWvdDnCXCXuHR+APqH4fbCtm2mp6eZn59H13WJuYXRaKSU'. + 'UiSTyVcBdV3XDcOwRaTU7/en19bWCn/79G+JL/76RbhZ22y7u+'. + '6ahl71nPDz/nO17m7wAxlabFOihy4+DvAcqAMbPzZ3OFzX5dmz'. + 'Z2iahoiosUUVhiGNRgPHcV4GzGQy5uLiYuH8+fMzo9FoslarJW'. + '9+elP75E+fBJu1zY7qqpqBUW3T/niohnVvy+1zm5aVtp+WE2XT'. + 'nrHFzbjh1tYLz3XdPjD4R3BKKba2tqhWq4dzUO3noBPn4H5PKy'. + 'LaO++8U7hx48byhQsXVne7u6tf3/v64t3P7mbq9+odt+OuaWi3'. + 'PLxbW2ytubjbQCgiMnt6VlaurWgz0zM0m02q1WrUaDSUUuqI56'. + 'ivDxE5MCgiYllWtlwuL5mmufLV/a/O/uXPf9Ff1F+80Lv6Yx29'. + '2qHzyZBh3cdvc7gaTZuZkzPh/Py8ACqVSv1/uPZDKXUAGEWRtF'. + 'qtxEcffZTL5XLF+2v39fqjeivshA/TpP83JLwzYFBzcA4370Cc'. + 'S81nTRBUs9lkOByi1GuOPI4Rh3+26JZlnSkWi781DOPXvV4v3+'. + '/2G0R8kSBxB/jew+tERK+c49m2TblcxrZtXNfl+fPneJ6HZVmU'. + 'y2VJJpNyaJ9TSinlOA5bW1u4rntkQA0oAG8D54gb9W3ianxM3A'. + 'e/cn73U3Hq1Cm5du2aPjs7a+ztcSIShmE4ajQa6tatWzQajZ+0'. + 'fbiKI+It4SvijVUj7kL2qvGfgkskEqTTaZmcnDROnTplJhIJTU'. + 'QiwPd9P/Q8T6XTaQzDIAiCfzjP/wFVfszuFqdHXgAAAABJRU5E'. + 'rkJggg==' ; + + + //========================================================== + // File: pp_red.png + //========================================================== + $this->imgdata_small[0][0]= 384 ; + $this->imgdata_small[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. + 'B3RJTUUH0wMJFhouFobZrQAAAQ1JREFUeJyV1dFtwyAQBuD/og'. + 'xQdYxa8gRY6hJ0jK6QdohMkTEuE5wUj5ERen05IoLvID7Jkn2G'. + 'j8MgTMyMXqRlUQBYq9ydmaL2h1cwqD7l30t+L1iwlbYFRegY7I'. + 'SHjkEifGg4ww3aBa/l4+9AhxWWr/dLhEunXUGHq6yGniw3QkOw'. + '3jJ7UBd82n/VVAlAtvsfp98lAj2sAJOhU4AeQ7DC1ubVBODWDJ'. + 'TtCsEWa6u5M1NeFs1NzgdtuhHGtj+9Q2IDppQUAL6Cyrlz0gDN'. + 'ohSMiJCt861672EiAhEhESG3woJ9V9OKTkwRKbdqz4cHmFLSFg'. + 's69+LvAZKdeZ/n89uLnd2g0S+gjd5g8zzjH5Y/eLLi+NPEAAAA'. + 'AElFTkSuQmCC' ; + + //========================================================== + // File: pp_orange.png + //========================================================== + $this->imgdata_small[1][0]= 403 ; + $this->imgdata_small[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. + 'B3RJTUUH0wMJFhwAnApz5AAAASBJREFUeJyN1dFthDAMBuDf7S'. + '3BCm2VCRKpS4QxbhikW6IewzcBqm6Fm6JyH7iEEByCn5AJH38g'. + 'BBIRHNUzBAWAGNfe/SrUGv92CtNt309BrfFdMGPjvt9CD8Fyml'. + 'ZZaDchRgA/59FDMD18pvNoNyHxMnUmgLmPHoJ+CqqfMaNAH22C'. + 'fgqKRwR+GRpxGjXBEiuXDBWQhTK3plxijyWWvtKVS5KNG1xM8I'. + 'OBr7geV1WupDqpmTAPKjCqLhxk/z0PImQmjKrAuI6vMXlhFroD'. + 'vfdqITXWqg2YMSJEAFcReoag6UXU2DzPG8w5t09YYsAyLWvHrL'. + 'HUy6D3XmvMAAhAay8kAJpBosX4vt0G4+4Jam6s6Rz1fgFG0ncA'. + 'f3XfOQcA+Acv5IUSdQw9hgAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: pp_pink.png + //========================================================== + $this->imgdata_small[2][0]= 419 ; + $this->imgdata_small[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. + 'B3RJTUUH0wMJFhsQzvz1RwAAATBJREFUeJyd1MFthDAQheF/oi'. + 'gF+JYWQKICkCJRA1vGtrDbxFbhGvY0HVjCLeS2BeTiHFgTB2wg'. + 'eRISstCnmcG2qCpbuXf3ADBQzWsPfZfS9y9HsEu4/Fo33Wf4Fx'. + 'gxL3a1XkI3wbTNXHLoboVeLFUYDqObYBy+Fw/Uh9DdCmtOwIjF'. + 'YvG76CZoOhNGRmpO8zz30CJoOhMAqlDxFzQLppgXj2XaNlP7FF'. + 'GLL7ccMYCBgZERgCvXLBrfi2DEclmiKZwFY4tp6sW26bVfnede'. + 'e5Hc5dC2bUgrXGKqWrwcXnNYDjmCrcCIiQgDcFYV05kQ8SXmnB'. + 'NgPiVN06wrTDGAhz5EWY/FOccTk+cTnHM/YNu2YYllgFxCWuUM'. + 'ikzGx+2Gc+4N+CoJW8n+5a2UKm2aBoBvGA6L7wfl8aoAAAAASU'. + 'VORK5CYII=' ; + + + //========================================================== + // File: pp_blue.png + //========================================================== + $this->imgdata_small[3][0]= 883 ; + $this->imgdata_small[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAMAAAC6V+0/AAACi1'. + 'BMVEX///8AAAAAADMAAGYAAJkAAMwAAP8zAAAzADMzAGYzAJkz'. + 'AMwzAP9mAABmADNmAGZmAJlmAMxmAP+ZAACZADOZAGaZAJmZAM'. + 'yZAP/MAADMADPMAGbMAJnMAMzMAP//AAD/ADP/AGb/AJn/AMz/'. + 'AP8AMwAAMzMAM2YAM5kAM8wAM/8zMwAzMzMzM2YzM5kzM8wzM/'. + '9mMwBmMzNmM2ZmM5lmM8xmM/+ZMwCZMzOZM2aZM5mZM8yZM//M'. + 'MwDMMzPMM2bMM5nMM8zMM///MwD/MzP/M2b/M5n/M8z/M/8AZg'. + 'AAZjMAZmYAZpkAZswAZv8zZgAzZjMzZmYzZpkzZswzZv9mZgBm'. + 'ZjNmZmZmZplmZsxmZv+ZZgCZZjOZZmaZZpmZZsyZZv/MZgDMZj'. + 'PMZmbMZpnMZszMZv//ZgD/ZjP/Zmb/Zpn/Zsz/Zv8AmQAAmTMA'. + 'mWYAmZkAmcwAmf8zmQAzmTMzmWYzmZkzmcwzmf9mmQBmmTNmmW'. + 'ZmmZlmmcxmmf+ZmQCZmTOZmWaZmZmZmcyZmf/MmQDMmTPMmWbM'. + 'mZnMmczMmf//mQD/mTP/mWb/mZn/mcz/mf8AzAAAzDMAzGYAzJ'. + 'kAzMwAzP8zzAAzzDMzzGYzzJkzzMwzzP9mzABmzDNmzGZmzJlm'. + 'zMxmzP+ZzACZzDOZzGaZzJmZzMyZzP/MzADMzDPMzGbMzJnMzM'. + 'zMzP//zAD/zDP/zGb/zJn/zMz/zP8A/wAA/zMA/2YA/5kA/8wA'. + '//8z/wAz/zMz/2Yz/5kz/8wz//9m/wBm/zNm/2Zm/5lm/8xm//'. + '+Z/wCZ/zOZ/2aZ/5mZ/8yZ///M/wDM/zPM/2bM/5nM/8zM////'. + '/wD//zP//2b//5n//8z///9jJVUgAAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. + 'RQfTAwkWGTNerea3AAAAYUlEQVR4nHXNwQ3AIAxDUUfyoROxRZ'. + 'icARin0EBTIP3Hp1gBRqSqYo0seqjZpnngojlWBir5+b8o06lM'. + 'ha5uFKEpDZulV8l52axhVzqaCdxQp32qVSSwC1wN3fYiw7b76w'. + 'bN4SMue4/KbwAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: pp_green.png + //========================================================== + $this->imgdata_small[4][0]= 447 ; + $this->imgdata_small[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. + 'B3RJTUUH0wMJFhkLdq9eKQAAAUxJREFUeJyN1LFVwzAQxvH/8f'. + 'IeDS0FLKABlN6eIwPYAzCHB0gWYI2jj+i1ABUTQN4TRSQ7iiWZ'. + 'qxLn9Mt9ydmiqrSq930AYFiu6YdKrf/hP1gYQn6960PxwBaYMG'. + 'E9UA3dBFtVQjdBOQmBakLennK0CapRwbZRZ3N0O/IeEsqp3HKL'. + 'Smtt5pUZgTPg4gdDud+6xoS97wM2rsxxmRSoTgoVcMZsXJkBho'. + 'SmKqCuOuEtls6nmGMFPTUmxBKx/MeyNfQGLoOOiC2ddsxb1Kzv'. + 'ZzUqu5IXbGDvBJf+hDisi77qFSuhq7Xpuu66TyJLRGbsXVUPxV'. + 'SxsgkzDMt0mKT3/RcjL8C5hHnvJToXY0xYRZ4xnVKsV/S+a8YA'. + 'AvCb3s9g13UhYj+TTo93B3fApRV1FVlEAD6H42DjN9/WvzDYuJ'. + 'dL5b1/ji+/IX8EGWP4AwRii8PdFHTqAAAAAElFTkSuQmCC' ; + } +} + +?> diff --git a/src/classes/jpgraph/imgdata_squares.inc.php b/src/classes/jpgraph/imgdata_squares.inc.php new file mode 100644 index 0000000..895dc93 --- /dev/null +++ b/src/classes/jpgraph/imgdata_squares.inc.php @@ -0,0 +1,150 @@ +'imgdata'); + + protected $colors = array('bluegreen','blue','green', + 'lightblue','orange','purple','red','yellow'); + protected $index = array('bluegreen' =>2,'blue'=>5,'green'=>6, + 'lightblue'=>0,'orange'=>7,'purple'=>4,'red'=>3,'yellow'=>1); + protected $maxidx = 7 ; + protected $imgdata ; + + function ImgData_Squares () { + //========================================================== + //sq_lblue.png + //========================================================== + $this->imgdata[0][0]= 362 ; + $this->imgdata[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAIAAADZrBkAAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMLFgojiPx/ygAAAPdJREFUeNpj/P377+kzHx89/c'. + 'VAHNBQ5VBX52HavPWWjg6nnDQbkXoUFTnnL7zD9PPXrz17HxCj'. + 'E6Jn6fL7H7/+ZWJgYCBGJ7IeBgYGJogofp1oehDa8OjE1IOiDa'. + 'tOrHoYGBhY0NwD0enirMDAwMDFxYRVD7ptyDrNTAU0NXix6sGu'. + 'jYGBgZOT9e/f/0xMjFyczFgVsGAKCfBza2kKzpl3hIuT1c9Xb/'. + 'PW58/foKchJqx6tmy98vbjj8cvPm/afMnXW1JShA2fNmQ9EBFc'. + 'Opnw6MGjkwm/Hlw6mQjqwaqTiRg9mDoZv//4M2/+UYJ64EBWgj'. + 'cm2hwA8l24oNDl+DMAAAAASUVORK5CYII=' ; + + //========================================================== + //sq_yellow.png + //========================================================== + $this->imgdata[1][0]= 338 ; + $this->imgdata[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAWl'. + 'BMVEX////+/+H+/9/9/9v8/8P8/8H8/7v8/7n6/4P5/335/3n5'. + '/3X4/1f4/1P3/031/w30/wn0/wPt+ADp9ADm8ADk7gDc5gDa5A'. + 'DL1ADFzgCwuACqsgClrABzeAC9M0MzAAAAAWJLR0QAiAUdSAAA'. + 'AAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9MDCxYEDlOgDj'. + 'EAAAB+SURBVHjaVcpbCsQgDEDRGERGKopjDa2a/W9zfLWj9/Nw'. + 'Ac21ZRBOtZlRN9ApzSYFaDUj79KIorRDbJNO9bN/GUSh2ZRJFJ'. + 'S18iorURBiyksO8buT0zkfYaUqzI91ckfhWhoGXTLzsDjI68Sz'. + 'pGMjrzPzauA/iXk1AtykmvgBC8UcWUdc9HkAAAAASUVORK5CYI'. + 'I=' ; + + //========================================================== + //sq_blgr.png + //========================================================== + $this->imgdata[2][0]= 347 ; + $this->imgdata[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAZl'. + 'BMVEX////0+vv0+vrz+fry+frv+Png7e/d7e/a6+zY6+250tSz'. + '0tSyztCtztGM0NWIz9SDzdNfsLVcrrRZrbJOp61MpqtIr7dHn6'. + 'RErrZArLQ6q7M2g4kygYcsp68npa4ctr8QZ20JnqepKsl4AAAA'. + 'AWJLR0QAiAUdSAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU'. + '1FB9MDCxYEByp8tpUAAAB7SURBVHjaVcjRFoIgDADQWZpWJpjY'. + 'MsnG//9kzIFn3McLzfArDA3MndFjrhvgfDHFBEB9pt0CVzwrY3'. + 'n2yicjhY4vTSp0nbXtN+hCV53SHDWe61dZY+/9463r2XuifHAM'. + '0SoH+6xEcovUlCfefeFSIwfTTQ3fB+pi4lV/bTIgvmaA7a0AAA'. + 'AASUVORK5CYII=' ; + + //========================================================== + //sq_red.png + //========================================================== + $this->imgdata[3][0]= 324 ; + $this->imgdata[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAXV'. + 'BMVEX////++Pn99/j99ff99fb98/X98/T98PL55uj43+P24+bw'. + 'kKPvjaHviJ3teJHpxMnoL2Pjs73WW3rWNljVWXnUVnbUK1DTJk'. + '3SUHPOBz/KQmmxPVmuOFasNFOeIkWVka/fAAAAAWJLR0QAiAUd'. + 'SAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9MDCxYEHd'. + 'ceT+8AAABtSURBVHjaVchbAkMwEAXQq6i3VrQiQfa/zDYTw8z5'. + 'PCjGt9JVWFt1XWPh1fWNdfDy+tq6WPfRUPENNKnSnXNWPB4uv2'. + 'b54nSZ8jHrMtOxvWZZZtpD4KP6xLkO9/AhzhaCOMhJh68cOjzV'. + '/K/4Ac2cG+nBcaRuAAAAAElFTkSuQmCC' ; + + //========================================================== + //sq_pink.png + //========================================================== + $this->imgdata[4][0]= 445 ; + $this->imgdata[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAApV'. + 'BMVEX////6+Pz69/v49Pr38/r17/jr4+/l3Onj2efh1ua/L+i+'. + 'q8m+Lue9Lua8qsS8LuW8LeS7pca5LOG4LN+2Y9O2YNW1ZdO1Kt'. + 'y0atC0aNGzb82zbc6zKtuzKdqycsuwa8qtJtOISZ2GRpuFN6GE'. + 'NqCDQpmCMZ+BPpd/LJ1/K519S5B9Jpx9Jpt9JZt6RY11BJZ1BJ'. + 'V0BJV0BJRzBJNvNoRtIoJUEmdZ/XbrAAAAAWJLR0QAiAUdSAAA'. + 'AAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9MDCxYDF3iKMD'. + 'YAAACeSURBVHjaVczbEoIgGARgCiMtrexoWpaa2FHUgvd/tH4Y'. + 'BnEvv9ldhNPradPnnGBUTtPDzMRPSIF46SaBoR25dYjz3I20Lb'. + 'ek6BgQz73Il7KKpSgCO0pTHU0886J1sCe0ZYbALjGhjFnEM2es'. + 'VhZVI4d+B1QtfnV47ywCEaKeP/p7JdLejSYt0j6NIiOq1wJZIs'. + 'QTDA0ELHwhPBCwyR/Cni9cOmzJtwAAAABJRU5ErkJggg==' ; + + //========================================================== + //sq_blue.png + //========================================================== + $this->imgdata[5][0]= 283 ; + $this->imgdata[5][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAQl'. + 'BMVEX////4+fz39/z19vvy8vru7/ni4+7g4fHW1ue8vteXmt6B'. + 'hdhiZ7FQVaZETcxCSJo1Oq4zNoMjKakhJHcKFaMEC2jRVYdWAA'. + 'AAAWJLR0QAiAUdSAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0'. + 'SU1FB9MDCxYDN0PkEP4AAABfSURBVHjaVchHAoAgDATAVcCCIF'. + 'j4/1elJEjmOFDHKVgDv4iz640gLs+LMF6ZUv/VqcXXplU7Gqpy'. + 'PFzBT5qml9NzlOX259riWHlS4kOffviHD8PQYZx2EFMPRkw+9Q'. + 'FSnRPeWEDzKAAAAABJRU5ErkJggg==' ; + + //========================================================== + //sq_green.png + //========================================================== + $this->imgdata[6][0]= 325 ; + $this->imgdata[6][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAXV'. + 'BMVEX////2+vX1+vX1+fT0+fPz+PPx9/Dv9u7u9e3h7uHe697a'. + '6dnO2s3I1sa10LOvza2ay5aEwYBWlE9TqE5Tkk1RkEpMrUJMg0'. + 'hKiUNGpEFBojw8oTcsbScaYBMWlwmMT0NtAAAAAWJLR0QAiAUd'. + 'SAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9MDCxYEFd'. + 'nFx90AAABuSURBVHjaVc9HAoAgDADB2HuJWLDx/2cKBITscW4L'. + '5byzMIWtZobNDZIZtrcCGZsRQ8GwvRSRNxIiMuysODKG3alikl'. + 'ueOPlpKTLBaRmOZxQxaXlfb5ZWI9om4WntrXiDSJzp7SBkwMQa'. + 'FEy0VR/NAB2kNuj7rgAAAABJRU5ErkJggg==' ; + + //========================================================== + //sq_orange.png + //========================================================== + $this->imgdata[7][0]= 321 ; + $this->imgdata[7][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAUV'. + 'BMVEX/////8+n/8uf/8OP/59H/5Mv/zqH/zJ3/ypv/yJf/vYH/'. + 'u33/uXn/n0n/nUX/m0H/lzn/ljf/lDP/kS3/kCv/iR//hxv/fg'. + 'n/fAX/eQDYZgDW6ia5AAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAL'. + 'EgAACxIB0t1+/AAAAAd0SU1FB9MDCxYEJIgbx+cAAAB2SURBVH'. + 'jaVczRCoQwDETRbLAWLZSGUA35/w/dVI0283i4DODew3YESmWW'. + 'kg5gWkoQAe6TleUQI/66Sy7i56+kLk7cht2N0+hcnJgQu0SqiC'. + '1SzSIbzWSi6gavqJ63wSduRi2f+kwyD5rEukwCdZ1kGAMGMfv9'. + 'AbWuGMOr5COSAAAAAElFTkSuQmCC' ; + } +} + +?> diff --git a/src/classes/jpgraph/imgdata_stars.inc.php b/src/classes/jpgraph/imgdata_stars.inc.php new file mode 100644 index 0000000..bc69690 --- /dev/null +++ b/src/classes/jpgraph/imgdata_stars.inc.php @@ -0,0 +1,144 @@ + 'imgdata'); + + protected $colors = array('bluegreen','lightblue','purple','blue','green','pink','red','yellow'); + protected $index = array('bluegreen'=>3,'lightblue'=>4,'purple'=>1, + 'blue'=>5,'green'=>0,'pink'=>7,'red'=>2,'yellow'=>6); + protected $maxidx = 7 ; + protected $imgdata ; + + function __construct() { + //========================================================== + // File: bstar_green_001.png + //========================================================== + $this->imgdata[0][0]= 329 ; + $this->imgdata[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAAUV'. + 'BMVEX///////+/v7+83rqcyY2Q/4R7/15y/1tp/05p/0lg/zdX'. + '/zdX/zVV/zdO/zFJ9TFJvDFD4yg+8Bw+3iU68hwurhYotxYosx'. + 'YokBoTfwANgQFUp7DWAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'. + 'HUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJj'. + 'CRyxgTAAAAcUlEQVR4nH3MSw6AIAwEUBL/IKBWwXL/g0pLojUS'. + 'ZzGLl8ko9Zumhr5iy66/GH0dp49llNPB5sTotDY5PVuLG6tnM9'. + 'CVKSIe1joSgPsAKSuANNaENFQvTAGzmheSkUpMBWeJZwqBT8wo'. + 'hmysD4bnnPsC/x8ItUdGPfAAAAAASUVORK5CYII=' ; + //========================================================== + // File: bstar_blred.png + //========================================================== + $this->imgdata[1][0]= 325 ; + $this->imgdata[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. + 'BMVEX///+/v79uRJ6jWPOSUtKrb+ejWO+gWPaGTruJTr6rZvF2'. + 'RqC2ocqdVuCeV+egV/GsnLuIXL66rMSpcOyATbipY/OdWOp+VK'. + 'aTU9WhV+yJKBoLAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJwynv1'. + 'XVAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. + 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. + 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. + 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bstar_red_001.png + //========================================================== + $this->imgdata[2][0]= 325 ; + $this->imgdata[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. + 'BMVEX///+/v7+eRFHzWG3SUmHnb37vWGr2WHG7Tlm+TljxZneg'. + 'Rk3KoaXgVmXnV2nxV227nJ++XGzErK3scIS4TVzzY3fqWG2mVF'. + 'zVU2PsV2rJFw9VAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJzCI0C'. + 'lSAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. + 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. + 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. + 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bstar_blgr_001.png + //========================================================== + $this->imgdata[3][0]= 325 ; + $this->imgdata[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. + 'BMVEX///+/v79Ehp5Yx/NSq9Jvw+dYwu9YzfZOmbtOmb5myPFG'. + 'gqChvcpWteBXvedXxvGcsbtcpb6su8RwzOxNmrhjyvNYwupUjK'. + 'ZTr9VXwOyJhmWNAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJTC65k'. + 'vQAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. + 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. + 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. + 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bstar_blgr_002.png + //========================================================== + $this->imgdata[4][0]= 325 ; + $this->imgdata[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. + 'BMVEX///+/v79EnpxY8/FS0dJv5+dY7+9Y9vBOubtOur5m8fFG'. + 'nKChycpW3uBX5+ZX8e2curtcvrqswsRw7OdNuLZj8/BY6udUpK'. + 'ZT1dRX7OtNkrW5AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJgXHeN'. + 'wwAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. + 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. + 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. + 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bstar_blue_001.png + //========================================================== + $this->imgdata[5][0]= 325 ; + $this->imgdata[5][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. + 'BMVEX///+/v79EY55Yi/NSetJvledYiO9YkPZOb7tObr5mkvFG'. + 'X6ChrcpWgOBXhedXi/Gcpbtcf76sssRwnOxNcbhjk/NYiepUbK'. + 'ZTfdVXh+ynNEzzAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJhStyP'. + 'zCAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. + 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. + 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. + 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bstar_oy_007.png + //========================================================== + $this->imgdata[6][0]= 325 ; + $this->imgdata[6][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. + 'BMVEX///+/v7+ejUTz11jSvVLn02/v1lj21li7q06+r07x2mag'. + 'lUbKxKHgy1bnz1fx1Ve7t5y+qlzEwqzs03C4pE3z2WPqz1imml'. + 'TVv1Ps01dGRjeyAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJjsGGc'. + 'GbAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. + 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. + 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. + 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bstar_lred.png + //========================================================== + $this->imgdata[7][0]= 325 ; + $this->imgdata[7][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. + 'BMVEX///+/v7+eRJPzWN3SUr7nb9TvWNj2WOS7Tqi+TqnxZtyg'. + 'Ro/KocPgVsjnV9LxV927nLa+XLTErL7scN24TarzY9/qWNemVJ'. + 'jVU8LsV9VCwcc9AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJxi9ZY'. + 'GoAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. + 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. + 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. + 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; + } +} + +?> diff --git a/src/classes/jpgraph/jpg-config.inc.php b/src/classes/jpgraph/jpg-config.inc.php index e5882bf..cfaad2a 100644 --- a/src/classes/jpgraph/jpg-config.inc.php +++ b/src/classes/jpgraph/jpg-config.inc.php @@ -137,5 +137,11 @@ define('CACHE_FILE_MOD',0664); // in GD. Turned off by default for speed define('USE_BRESENHAM',false); +// Default theme class name +define('DEFAULT_THEME_CLASS', 'UniversalTheme'); -?> +define('SUPERSAMPLING', true); +define('SUPERSAMPLING_SCALE', 1); + + +?> \ No newline at end of file diff --git a/src/classes/jpgraph/jpgraph.php b/src/classes/jpgraph/jpgraph.php index f5df2af..b955246 100644 --- a/src/classes/jpgraph/jpgraph.php +++ b/src/classes/jpgraph/jpgraph.php @@ -5,7 +5,7 @@ // Created: 2001-01-08 // Ver: $Id: jpgraph.php 1924 2010-01-11 14:03:26Z ljp $ // -// Copyright (c) Aditus Consulting. All rights reserved. +// Copyright (c) Asial Corporation. All rights reserved. //======================================================================== require_once('jpg-config.inc.php'); @@ -15,10 +15,11 @@ require_once('jpgraph_ttf.inc.php'); require_once('jpgraph_rgb.inc.php'); require_once('jpgraph_text.inc.php'); require_once('jpgraph_legend.inc.php'); +require_once('jpgraph_theme.inc.php'); require_once('gd_image.inc.php'); // Version info -define('JPG_VERSION','3.0.7'); +define('JPG_VERSION','4.0.1'); // Minimum required PHP version define('MIN_PHPVERSION','5.1.0'); @@ -160,6 +161,7 @@ define("_JPG_DEBUG",false); define("_FORCE_IMGTOFILE",false); define("_FORCE_IMGDIR",'/tmp/jpgimg/'); + // // Automatic settings of path for cache and font directory // if they have not been previously specified @@ -229,13 +231,16 @@ function CheckPHPVersion($aMinVersion) { list($majorC, $minorC, $editC) = preg_split('/[\/.-]/', PHP_VERSION); list($majorR, $minorR, $editR) = preg_split('/[\/.-]/', $aMinVersion); - if ($majorC != $majorR) return false; if ($majorC < $majorR) return false; - // same major - check minor - if ($minorC > $minorR) return true; - if ($minorC < $minorR) return false; - // and same minor - if ($editC >= $editR) return true; + + if ($majorC == $majorR) { + if($minorC < $minorR) return false; + + if($minorC == $minorR){ + if($editC < $editR) return false; + } + } + return true; } @@ -500,12 +505,12 @@ class Graph { public $cache_name; // File name to be used for the current graph in the cache directory public $xgrid=null; // X Grid object (linear or logarithmic) public $ygrid=null,$y2grid=null; //dito for Y - public $doframe=true,$frame_color='black', $frame_weight=1; // Frame around graph + public $doframe,$frame_color, $frame_weight; // Frame around graph public $boxed=false, $box_color='black', $box_weight=1; // Box around plot area public $doshadow=false,$shadow_width=4,$shadow_color='gray@0.5'; // Shadow for graph public $xaxis=null; // X-axis (instane of Axis class) public $yaxis=null, $y2axis=null, $ynaxis=array(); // Y axis (instance of Axis class) - public $margin_color=array(230,230,230); // Margin color of graph + public $margin_color; // Margin color of graph public $plotarea_color=array(255,255,255); // Plot area color public $title,$subtitle,$subsubtitle; // Title and subtitle(s) text object public $axtype="linlin"; // Type of axis @@ -536,15 +541,15 @@ class Graph { public $titlebackground = false; public $titlebackground_color = 'lightblue', $titlebackground_style = 1, - $titlebackground_framecolor = 'blue', - $titlebackground_framestyle = 2, - $titlebackground_frameweight = 1, - $titlebackground_bevelheight = 3 ; + $titlebackground_framecolor, + $titlebackground_framestyle, + $titlebackground_frameweight, + $titlebackground_bevelheight; public $titlebkg_fillstyle=TITLEBKG_FILLSTYLE_SOLID; public $titlebkg_scolor1='black',$titlebkg_scolor2='white'; - public $framebevel = false, $framebeveldepth = 2 ; - public $framebevelborder = false, $framebevelbordercolor='black'; - public $framebevelcolor1='white@0.4', $framebevelcolor2='black@0.4'; + public $framebevel, $framebeveldepth; + public $framebevelborder, $framebevelbordercolor; + public $framebevelcolor1, $framebevelcolor2; public $background_image_mix=100; public $background_cflag = ''; public $background_cflag_type = BGIMG_FILLPLOT; @@ -555,6 +560,7 @@ class Graph { $iImgTransFillColor='white',$iImgTransHighQ=false, $iImgTransBorder=false,$iImgTransHorizonPos=0.5; public $legend; + public $graph_theme; protected $iYAxisDeltaPos=50; protected $iIconDepth=DEPTH_BACK; protected $iAxisLblBgType = 0, @@ -562,6 +568,10 @@ class Graph { $iYAxisLblBgFillColor = 'lightgray', $iYAxisLblBgColor = 'black'; protected $iTables=NULL; + protected $isRunningClear = false; + protected $inputValues; + protected $isAfterSetScale = false; + // aWIdth Width in pixels of image // aHeight Height in pixels of image // aCachedName Name for image file in cache directory @@ -574,6 +584,9 @@ class Graph { JpGraphError::RaiseL(25008);//('Image width/height argument in Graph::Graph() must be numeric'); } + // Initialize frame and margin + $this->InitializeFrameAndMargin(); + // Automatically generate the image file name based on the name of the script that // generates the graph if( $aCachedName == 'auto' ) { @@ -592,7 +605,7 @@ class Graph { $this->title = new Text(); $this->title->ParagraphAlign('center'); - $this->title->SetFont(FF_FONT2,FS_BOLD); + $this->title->SetFont(FF_DEFAULT,FS_NORMAL); //FF_FONT2, FS_BOLD $this->title->SetMargin(5); $this->title->SetAlign('center'); @@ -620,6 +633,42 @@ class Graph { $this->SetTickDensity(); // Normal density $this->tabtitle = new GraphTabTitle(); + + if (!$this->isRunningClear) { + $this->inputValues = array(); + $this->inputValues['aWidth'] = $aWidth; + $this->inputValues['aHeight'] = $aHeight; + $this->inputValues['aCachedName'] = $aCachedName; + $this->inputValues['aTimeout'] = $aTimeout; + $this->inputValues['aInline'] = $aInline; + + $theme_class = DEFAULT_THEME_CLASS; + if (class_exists($theme_class)) { + $this->graph_theme = new $theme_class(); + } + } + } + + function InitializeFrameAndMargin() { + $this->doframe=true; + $this->frame_color='black'; + $this->frame_weight=1; + + $this->titlebackground_framecolor = 'blue'; + $this->titlebackground_framestyle = 2; + $this->titlebackground_frameweight = 1; + $this->titlebackground_bevelheight = 3; + $this->titlebkg_fillstyle=TITLEBKG_FILLSTYLE_SOLID; + $this->titlebkg_scolor1='black'; + $this->titlebkg_scolor2='white'; + $this->framebevel = false; + $this->framebeveldepth = 2; + $this->framebevelborder = false; + $this->framebevelbordercolor='black'; + $this->framebevelcolor1='white@0.4'; + $this->framebevelcolor2='black@0.4'; + + $this->margin_color = array(250,250,250); } function SetupCache($aFilename,$aTimeout=60) { @@ -736,6 +785,10 @@ class Graph { $this->plots[] = $aPlot; } } + + if ($this->graph_theme) { + $this->graph_theme->SetupPlot($aPlot); + } } function AddTable($aTable) { @@ -785,6 +838,10 @@ class Graph { else { $this->y2plots[] = $aPlot; } + + if ($this->graph_theme) { + $this->graph_theme->SetupPlot($aPlot); + } } // Add plot to the extra Y-axises @@ -809,6 +866,10 @@ class Graph { else { $this->ynplots[$aN][] = $aPlot; } + + if ($this->graph_theme) { + $this->graph_theme->SetupPlot($aPlot); + } } // Add text object to the graph @@ -1058,6 +1119,21 @@ class Graph { $this->xgrid = new Grid($this->xaxis); $this->ygrid = new Grid($this->yaxis); $this->ygrid->Show(); + + + if (!$this->isRunningClear) { + $this->inputValues['aAxisType'] = $aAxisType; + $this->inputValues['aYMin'] = $aYMin; + $this->inputValues['aYMax'] = $aYMax; + $this->inputValues['aXMin'] = $aXMin; + $this->inputValues['aXMax'] = $aXMax; + + if ($this->graph_theme) { + $this->graph_theme->ApplyGraph($this); + } + } + + $this->isAfterSetScale = true; } // Specify secondary Y scale @@ -1084,6 +1160,10 @@ class Graph { // Deafult position is the max x-value $this->y2grid = new Grid($this->y2axis); + + if ($this->graph_theme) { + $this->graph_theme->ApplyGraph($this); + } } // Set the delta position (in pixels) between the multiple Y-axis @@ -1111,6 +1191,10 @@ class Graph { $this->ynaxis[$aN] = new Axis($this->img,$this->ynscale[$aN]); $this->ynaxis[$aN]->scale->ticks->SetDirection(SIDE_LEFT); $this->ynaxis[$aN]->SetLabelSide(SIDE_RIGHT); + + if ($this->graph_theme) { + $this->graph_theme->ApplyGraph($this); + } } // Specify density of ticks when autoscaling 'normal', 'dense', 'sparse', 'verysparse' @@ -1508,9 +1592,16 @@ class Graph { } function AdjustMarginsForTitles() { - $totrequired = ($this->title->t != '' ? $this->title->GetTextHeight($this->img) + $this->title->margin + 5 : 0 ) + - ($this->subtitle->t != '' ? $this->subtitle->GetTextHeight($this->img) + $this->subtitle->margin + 5 : 0 ) + - ($this->subsubtitle->t != '' ? $this->subsubtitle->GetTextHeight($this->img) + $this->subsubtitle->margin + 5 : 0 ) ; + $totrequired = + ($this->title->t != '' + ? $this->title->GetTextHeight($this->img) + $this->title->margin + 5 * SUPERSAMPLING_SCALE + : 0 ) + + ($this->subtitle->t != '' + ? $this->subtitle->GetTextHeight($this->img) + $this->subtitle->margin + 5 * SUPERSAMPLING_SCALE + : 0 ) + + ($this->subsubtitle->t != '' + ? $this->subsubtitle->GetTextHeight($this->img) + $this->subsubtitle->margin + 5 * SUPERSAMPLING_SCALE + : 0 ) ; $btotrequired = 0; if($this->xaxis != null && !$this->xaxis->hide && !$this->xaxis->hide_labels ) { @@ -1545,13 +1636,24 @@ class Graph { // DO Nothing. It gets too messy to do this properly for 90 deg... } else{ + // need more top margin if( $this->img->top_margin < $totrequired ) { - $this->SetMargin($this->img->left_margin,$this->img->right_margin, - $totrequired,$this->img->bottom_margin); + $this->SetMargin( + $this->img->raw_left_margin, + $this->img->raw_right_margin, + $totrequired / SUPERSAMPLING_SCALE, + $this->img->raw_bottom_margin + ); } + + // need more bottom margin if( $this->img->bottom_margin < $btotrequired ) { - $this->SetMargin($this->img->left_margin,$this->img->right_margin, - $this->img->top_margin,$btotrequired); + $this->SetMargin( + $this->img->raw_left_margin, + $this->img->raw_right_margin, + $this->img->raw_top_margin, + $btotrequired / SUPERSAMPLING_SCALE + ); } } } @@ -1907,7 +2009,6 @@ class Graph { // $aStrokeFileName If != "" the image will be written to this file and NOT // streamed back to the browser function Stroke($aStrokeFileName='') { - // Fist make a sanity check that user has specified a scale if( empty($this->yscale) ) { JpGraphError::RaiseL(25031);//('You must specify what scale to use with a call to Graph::SetScale().'); @@ -1951,6 +2052,10 @@ class Graph { // Setup pre-stroked adjustments and Legends $this->doPrestrokeAdjustments(); + if ($this->graph_theme) { + $this->graph_theme->PreStrokeApply($this); + } + // Bail out if any of the Y-axis not been specified and // has no plots. (This means it is impossible to do autoscaling and // no other scale was given so we can't possible draw anything). If you use manual @@ -2597,7 +2702,7 @@ class Graph { } $this->img->SetColor($this->margin_color); - // $this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->height-1-$vadj); + $this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->height-1-$vadj); $this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->top_margin); $this->img->FilledRectangle(0,$this->img->top_margin,$this->img->left_margin,$this->img->height-1-$hadj); @@ -2638,7 +2743,7 @@ class Graph { $aa = $this->img->SetAngle(0); $this->StrokeFrame(); $aa = $this->img->SetAngle($aa); - $this->StrokeBackgroundGrad(); + $this->StrokeBackgroundGrad(); if( $this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_MARGIN) ) { $this->FillPlotArea(); } @@ -2982,6 +3087,79 @@ class Graph { return array($min,$max); } + function hasLinePlotAndBarPlot() { + $has_line = false; + $has_bar = false; + + foreach ($this->plots as $plot) { + if ($plot instanceof LinePlot) { + $has_line = true; + } + if ($plot instanceof BarPlot) { + $has_bar = true; + } + } + + if ($has_line && $has_bar) { + return true; + } + + return false; + } + + function SetTheme($graph_theme) { + + if (!($this instanceof PieGraph)) { + if (!$this->isAfterSetScale) { + JpGraphError::RaiseL(25133);//('Use Graph::SetTheme() after Graph::SetScale().'); + } + } + + if ($this->graph_theme) { + $this->ClearTheme(); + } + $this->graph_theme = $graph_theme; + $this->graph_theme->ApplyGraph($this); + } + + function ClearTheme() { + $this->graph_theme = null; + + $this->isRunningClear = true; + + $this->__construct( + $this->inputValues['aWidth'], + $this->inputValues['aHeight'], + $this->inputValues['aCachedName'], + $this->inputValues['aTimeout'], + $this->inputValues['aInline'] + ); + + if (!($this instanceof PieGraph)) { + if ($this->isAfterSetScale) { + $this->SetScale( + $this->inputValues['aAxisType'], + $this->inputValues['aYMin'], + $this->inputValues['aYMax'], + $this->inputValues['aXMin'], + $this->inputValues['aXMax'] + ); + } + } + + $this->isRunningClear = false; + } + + function SetSupersampling($do = false, $scale = 2) { + if ($do) { + define('SUPERSAMPLING_SCALE', $scale); + // $this->img->scale = $scale; + } else { + define('SUPERSAMPLING_SCALE', 1); + //$this->img->scale = 0; + } + } + } // Class //=================================================== @@ -2989,7 +3167,7 @@ class Graph { // Description: Holds properties for a line //=================================================== class LineProperty { - public $iWeight=1, $iColor='black', $iStyle='solid', $iShow=true; + public $iWeight=1, $iColor='black', $iStyle='solid', $iShow=false; function __construct($aWeight=1,$aColor='black',$aStyle='solid') { $this->iWeight = $aWeight; @@ -3342,7 +3520,7 @@ class SuperScriptText extends Text { class Grid { protected $img; protected $scale; - protected $majorcolor='#DDDDDD',$minorcolor='#EEEEEE'; + protected $majorcolor='#CCCCCC',$minorcolor='#DDDDDD'; protected $majortype='solid',$minortype='solid'; protected $show=false, $showMinor=false,$majorweight=1,$minorweight=1; protected $fill=false,$fillcolor=array('#EFEFEF','#BBCCFF'); @@ -3435,7 +3613,7 @@ class Grid { for($i=0; $i < $nbrgrids; ++$i) { $y=$aTicksPos[$i]; - $this->img->StyleLine($xl,$y,$xr,$y,$style); + $this->img->StyleLine($xl,$y,$xr,$y,$style,true); } } elseif( $this->scale->type == 'x' ) { @@ -3466,9 +3644,9 @@ class Grid { $x=$aTicksPos[$i]; while( $iimg->Line($x,$yl,$x,$yu); - elseif( $aType == 'dotted' ) $this->img->DashedLine($x,$yl,$x,$yu,1,6); - elseif( $aType == 'dashed' ) $this->img->DashedLine($x,$yl,$x,$yu,2,4); - elseif( $aType == 'longdashed' ) $this->img->DashedLine($x,$yl,$x,$yu,8,6); + elseif( $aType == 'dotted' ) $this->img->DashedLineForGrid($x,$yl,$x,$yu,1,6); + elseif( $aType == 'dashed' ) $this->img->DashedLineForGrid($x,$yl,$x,$yu,2,4); + elseif( $aType == 'longdashed' ) $this->img->DashedLineForGrid($x,$yl,$x,$yu,8,6); ++$i; } } @@ -3492,7 +3670,7 @@ class AxisPrototype { public $img=null; public $hide=false,$hide_labels=false; public $title=null; - public $font_family=FF_FONT1,$font_style=FS_NORMAL,$font_size=12,$label_angle=0; + public $font_family=FF_DEFAULT,$font_style=FS_NORMAL,$font_size=8,$label_angle=0; public $tick_step=1; public $pos = false; public $ticks_label = array(); @@ -3732,13 +3910,21 @@ class Axis extends AxisPrototype { $pos=$aOtherAxisScale->Translate(0); } } + $pos += $this->iDeltaAbsPos; $this->img->SetLineWeight($this->weight); $this->img->SetColor($this->color); $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); + if( $this->scale->type == "x" ) { if( !$this->hide_line ) { - $this->img->FilledRectangle($this->img->left_margin,$pos,$this->img->width-$this->img->right_margin,$pos+$this->weight-1); + // Stroke X-axis + $this->img->FilledRectangle( + $this->img->left_margin, + $pos, + $this->img->width - $this->img->right_margin, + $pos + $this->weight-1 + ); } if( $this->title_side == SIDE_DOWN ) { $y = $pos + $this->img->GetFontHeight() + $this->title_margin + $this->title->margin; @@ -3766,8 +3952,15 @@ class Axis extends AxisPrototype { // Add line weight to the height of the axis since // the x-axis could have a width>1 and we want the axis to fit nicely together. if( !$this->hide_line ) { - $this->img->FilledRectangle($pos-$this->weight+1,$this->img->top_margin,$pos,$this->img->height-$this->img->bottom_margin+$this->weight-1); + // Stroke Y-axis + $this->img->FilledRectangle( + $pos - $this->weight + 1, + $this->img->top_margin, + $pos, + $this->img->height - $this->img->bottom_margin + $this->weight - 1 + ); } + $x=$pos ; if( $this->title_side == SIDE_LEFT ) { $x -= $this->title_margin; @@ -4259,7 +4452,11 @@ class LinearTicks extends Ticks { } } elseif( $aScale->type == "y" ) { + //@todo s=2:20,12 s=1:50,6 $this->major_step:$nbr + // abs_point,limit s=1:270,80 s=2:540,160 + // $this->major_step = 50; $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal())/$this->major_step)+1; +// $step = 5; while( round($abs_pos) >= $limit ) { $this->ticks_pos[$i] = round($abs_pos); $this->ticks_label[$i]=$label; @@ -4287,7 +4484,7 @@ class LinearTicks extends Ticks { // If precision hasn't been specified set it to a sensible value if( $this->precision==-1 ) { $t = log10($this->minor_step); - if( $t > 0 ) { + if( $t > 0 || $t === 0.0) { $precision = 0; } else { @@ -4475,12 +4672,13 @@ class LinearScale { public $name = 'lin'; public $auto_ticks=false; // When using manual scale should the ticks be automatically set? public $world_abs_size; // Plot area size in pixels (Needed public in jpgraph_radar.php) - public $world_size; // Plot area size in world coordinates public $intscale=false; // Restrict autoscale to integers protected $autoscale_min=false; // Forced minimum value, auto determine max protected $autoscale_max=false; // Forced maximum value, auto determine min private $gracetop=0,$gracebottom=0; + private $_world_size; // Plot area size in world coordinates + function __construct($aMin=0,$aMax=0,$aType='y') { assert($aType=='x' || $aType=='y' ); assert($aMin<=$aMax); @@ -4839,7 +5037,7 @@ class LinearScale { if( $this->world_size<=0 ) { // This should never ever happen !! JpGraphError::RaiseL(25074); - //("You have unfortunately stumbled upon a bug in JpGraph. It seems like the scale range is ".$this->world_size." [for ".$this->type." scale]
Please report Bug #01 to jpgraph@aditus.nu and include the script that gave this error. This problem could potentially be caused by trying to use \"illegal\" values in the input data arrays (like trying to send in strings or only NULL values) which causes the autoscaling to fail."); + //("You have unfortunately stumbled upon a bug in JpGraph. It seems like the scale range is ".$this->world_size." [for ".$this->type." scale]
Please report Bug #01 to info@jpgraph.net and include the script that gave this error. This problem could potentially be caused by trying to use \"illegal\" values in the input data arrays (like trying to send in strings or only NULL values) which causes the autoscaling to fail."); } // scale_factor = number of pixels per world unit @@ -5018,6 +5216,20 @@ class LinearScale { } return 3; // $c smallest } + + function __get($name) { + $variable_name = '_' . $name; + + if (isset($this->$variable_name)) { + return $this->$variable_name * SUPERSAMPLING_SCALE; + } else { + JpGraphError::RaiseL('25132', $name); + } + } + + function __set($name, $value) { + $this->{'_'.$name} = $value; + } } // Class @@ -5030,7 +5242,7 @@ class DisplayValue { public $show=false; public $valign='',$halign='center'; public $format='%.1f',$negformat=''; - private $ff=FF_FONT1,$fs=FS_NORMAL,$fsize=10; + private $ff=FF_DEFAULT,$fs=FS_NORMAL,$fsize=8; private $iFormCallback=''; private $angle=0; private $color='navy',$negcolor=''; @@ -5050,7 +5262,7 @@ class DisplayValue { $this->negcolor = $aNegcolor; } - function SetFont($aFontFamily,$aFontStyle=FS_NORMAL,$aFontSize=10) { + function SetFont($aFontFamily,$aFontStyle=FS_NORMAL,$aFontSize=8) { $this->ff=$aFontFamily; $this->fs=$aFontStyle; $this->fsize=$aFontSize; @@ -5175,11 +5387,21 @@ class Plot { protected $weight=1; protected $center=false; + protected $inputValues; + protected $isRunningClear = false; + function __construct($aDatay,$aDatax=false) { $this->numpoints = count($aDatay); if( $this->numpoints==0 ) { JpGraphError::RaiseL(25121);//("Empty input data array specified for plot. Must have at least one data point."); } + + if (!$this->isRunningClear) { + $this->inputValues = array(); + $this->inputValues['aDatay'] = $aDatay; + $this->inputValues['aDatax'] = $aDatax; + } + $this->coords[0]=$aDatay; if( is_array($aDatax) ) { $this->coords[1]=$aDatax; @@ -5345,6 +5567,12 @@ class Plot { } } + function Clear() { + $this->isRunningClear = true; + $this->__construct($this->inputValues['aDatay'], $this->inputValues['aDatax']); + $this->isRunningClear = false; + } + } // Class diff --git a/src/classes/jpgraph/jpgraph_antispam-digits.php b/src/classes/jpgraph/jpgraph_antispam-digits.php new file mode 100644 index 0000000..d9d350c --- /dev/null +++ b/src/classes/jpgraph/jpgraph_antispam-digits.php @@ -0,0 +1,205 @@ +digits['6'][0]= 645 ; + $this->digits['6'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAEBAAMBAAAAAAAAAAAAAAAABgMEBwX/xAAvEAABAwMC'. + 'BAQEBwAAAAAAAAABAgMEAAURBiESIjFRBxMUQRUWMmFTYnGRkrHC/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFhEBAQEAAAAA'. + 'AAAAAAAAAAAAAAER/9oADAMBAAIRAxEAPwDslwiR3oDku8ONttsAvDiVyMcO/ET7ke5/aoOz6k1Vr5htNjW7a7M1yO3NTQU9JUDu'. + 'GgrlSn8xyf6p4gXaHJvNps9/mKZtSkGdMjRwpfqAFBLLACRlZUrJONsI2717No1lbZ10kx7XGnRpKWQ/6GVGMfzEJ5VFIVtsOH6e'. + 'wyKVhYsia0y22pLThSkJK1uniVgdThOM0ol+StIUhpopIyCFq3H8aUVCwnG3PGe4Rp6fLXJtMdyM0ojcIWvIz3HFnAPfrWTXb6GN'. + 'WaLXDwZjVz8pKEfhuIUFg/bAz9sVJ61nt61mxJFslLtq7e5yPqiBT4UDklKw4MDpt+u+9bFiu9riXNu83R+fcr6tohuQ5HQhmK37'. + 'paaC8DruScmg6X8KkjZEhbaB9KEyFYSOw26Uqd+e7Qerl5z74DY/1SomP//Z' ; + + //========================================================== + // d2-small.jpg + //========================================================== + $this->digits['2'][0]= 606 ; + $this->digits['2'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEQMBIgACEQEDEQH/xAAYAAEBAQEBAAAAAAAAAAAAAAAFAAQHAv/EACsQAAEDBAEC'. + 'BAYDAAAAAAAAAAIBAwQABQYRIRIxQVFhcQcTFSJSU5GU0f/EABcBAAMBAAAAAAAAAAAAAAAAAAECAwT/xAAZEQACAwEAAAAAAAAA'. + 'AAAAAAAAARESUUH/2gAMAwEAAhEDEQA/AOqXm/Q8dxmOL4PPSnCSNFixx6nXnkXgRT3Te17JWbGsveueSyLZdbPItNxOKLzTLjou'. + 'gYCSoSoY8ISKSbFeUrzkdlnTL1YshskiErkQnFEZaF8kkdBBVdjyi6RNL5+9F486eS/ECVkcBtDt1vZcho5viS8ZCp9C9tAIAm/F'. + 'VoPRU+HRtJ5JVRP1kP0PfwP+1VKrHBMliXG4Nw8VgE4xGkuqk2S1wTUNEVdIvgpL9iL6KtNxY7WOwo9tt0RCitj0sR2uCbFPPzH1'. + '7+6rRuSRcljMBMsUy2tky045KOawZk5xtEFBJEROO3hx61kh2rPCIX3MhsyC4QmfTbC6lH8dq5212qwkiG5H6Y/9R2qm+ofxqqsL'. + 'DLZ6f//Z' ; + + //========================================================== + // d9-small.jpg + //========================================================== + $this->digits['9'][0]= 680 ; + $this->digits['9'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwP/xAArEAABAwMD'. + 'AgYBBQAAAAAAAAABAgMEBQYRABIhE1EUIjEzQUIHMlJhcdH/xAAWAQEBAQAAAAAAAAAAAAAAAAACAQD/xAAYEQEAAwEAAAAAAAAA'. + 'AAAAAAAAAREhQf/aAAwDAQACEQMRAD8AkK7brF6X7XpMeGoKhFMLEeT4ZUheEhanF4OcZ2pTgDykk92bZpdCsi7aezLjxkIPUZiV'. + 'RSCy8hah7EkZ27yM7V+iscal5bE22Lon1qNDmSKROd8Sl+Ix1lMOlIS4HGgQpbStoUCnlJz8HmsXtW3Lst2rmBAelLMRRekOwnYz'. + 'Edls9QKKnOVLyk7UgcbzzrdBthqEJJwZbAI4x1U/7o1TaFa9lG36aXaZTy54VrcXUgrzsGdx+T30aNydweqVw1GS87T6Lb86Q4ha'. + 'my/IAYjZBx+snKk99oOQMf1AViE65SY348hzFy6hPKnqtKz7DC1lbqyPrvJKUJ7H+M6Wrt3InP7o1brFNp4bCDGhxGAsqz69VSiQ'. + 'ORwBxrrQ7itm1ac7Hp0WoGTIc3PSn0pccdcP2WorycfA1RaRHjxosZqOyhtDTSAhCf2gDAGjVHTd9sKSCumynFEZK1tIJUe58/ro'. + '1V1//9k=' ; + + //========================================================== + // d5-small.jpg + //========================================================== + $this->digits['5'][0]= 632 ; + $this->digits['5'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgIFBwT/xAAoEAABAwME'. + 'AQQCAwAAAAAAAAABAgMEBQYRABIhIkEUMVFhBxNCgaH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAv/EABcRAQEBAQAAAAAAAAAAAAAA'. + 'AAABEUH/2gAMAwEAAhEDEQA/ANGvW4YVOeiRX5b4mv5Sin05IdlupPKdo/j2SO3+6TbPNQvOsTVz33KRT4csR3YUF7Dsh5OSFvug'. + 'kqG4FPBxnjxpvvi4KZb1pTpU+QwxUi2Y7ZIAefUk5ATxnB9/gbtL/wCH1UpuhPUlZlMVaQ0mS8zJjqZOPfc2TwpIUonI9tw40R1r'. + 'WNGq/wBdJR1XT3lqHBUnGCfkfWjRWs1ve249erQqQYjOtN1FqPUpCXQ4WIzQSsJwT0UpRwQPG0nzqyuNHobjsl9kBuWqoOoXtT1/'. + 'WppZcA8lKRj64HxqU+3KpAr6plElRVKef3S4E0K9O8pLXVzKcqSsJAB9wSAca6bSoNXeuA1+5pEV+SGFNU1iKVFqI0Vdx2AJUeoz'. + '8DGlTDwG3CAf3q/pI0ah6MDhLz6U+EpXwPoaNMU//9k=' ; + + //========================================================== + // d1-small.jpg + //========================================================== + $this->digits['1'][0]= 646 ; + $this->digits['1'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEwMBIgACEQEDEQH/xAAZAAADAAMAAAAAAAAAAAAAAAAABQYCBAf/xAApEAACAQMD'. + 'AwQBBQAAAAAAAAABAgMEBREABiESMUEHEyJRkSNCYXGB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFxEBAQEBAAAAAAAAAAAA'. + 'AAAAAAEREv/aAAwDAQACEQMRAD8A6jdd4WLbstILnc4Uq0VoWpkJknb6IjXLHJUePOlez923fcW4r1SxWlqC2UbdKirQif3Xw3yA'. + 'OFAGT09/kO3OmV3a20MFRf6lIYPcpy7yRRAzgxjIy2M8YwcdiBzpX6d22VNvUlTXsFkuwkrKqNSfnK7F8OTzwrAY+l5zoxKskudN'. + 'EgQPUT9PBkWF3DH+1GPxo1mLnRoAqF2VRgGOFmX/AAgY/GjRUP6hVMFv2FuFqUvUGrpDFJMBnpdyF5bsAQew7Hxzp6LZNT0yQ1DI'. + 'wp0QCFBhD0jCsfLZHxbx5xxpTuvb1+v9PV7Ztk9roLPLCjmSSN3mX5ZwqjCgZX7PfWxDQb2in96pv9qq46aTE0bW4x9ceAWAYPwS'. + 'PsYzoixgmheBGjIVcYCnjp/jHjHbRpe1JLn9OnopE/a0ykvjwDx47aNMXqP/2Q==' ; + + //========================================================== + // d8-small.jpg + //========================================================== + $this->digits['8'][0]= 694 ; + $this->digits['8'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AFQMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABgcEBf/EACsQAAEDAwMD'. + 'AwMFAAAAAAAAAAECAwQFBhEAEiEUMVEHE0EVYYEiIzJCsf/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/EABcRAQEBAQAAAAAAAAAA'. + 'AAAAAAABERL/2gAMAwEAAhEDEQA/AKL6gVVUa0i1T5QjvTprUJMlxW4R9zgQXe/AH+kaWrntqlWjaq7gpcmotXAw82ht9yY4tch8'. + 'uAFC0k7VBXPGMY51ruiaue+bThIj+7NbWqS+7HDxajFf6AlB/k44o8ZOABk4xkL0X0tZiojKrlRuGRJjugqldSlKGf6t7BuUQe3J'. + '44xxxrA1a4KVJipLidri8uLHgqOcfjOPxo0o2hdDvS1CmV2Yl6fS5ioipIQR1CAlKkLKR2UUqAI8g6NRSwuuyHab6s1ufLI/Zai7'. + 'UBJOxhTS0+6B32pWSFH4CidOdWU0ukLiN1BLr0zG5Sdm3GRvcPhIT858DvjXNrVsSLnm/VIdTXS6tTnFsxZTSN3jchaTwps+O/z9'. + 'tcBVq3hIX0tYqlIiQHdy5CqRHKHXEjAOMgBKjnvyRk4xrQa7OiGt1K5biYZL8SoVEpjOqkFsONtJCNwASeCQrn7aNUKnQYtLp7EC'. + 'EylmLHQltptPZKQOBo1FzH//2Q==' ; + + //========================================================== + // d4-small.jpg + //========================================================== + $this->digits['4'][0]= 643 ; + $this->digits['4'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABAYHAv/EAC0QAAIBAwQA'. + 'BAMJAAAAAAAAAAECAwQFEQAGEiETFDFBUmGBByIjUVNxobHR/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAIB/8QAGBEBAAMBAAAAAAAA'. + 'AAAAAAAAAAERIVH/2gAMAwEAAhEDEQA/ANjM00Nxmt1xiWW31CZp5uJwoAAaOQ/n7qfcZHqO5my3q5XX7R6ijiqnNut9u4NyJ4yv'. + 'JJyjYr8Xhrn5g599J7x3ulBNU7Zo7dXXXcLQ8kURYi4epYtkALjOePv1nUvbLvV7P3BZm3DR3eh88Kp7pVzBZI6iUhGWRRGWwE44'. + 'HX3V+uiL1uHgt+vL/H+aNJQ3CSeCOaFqSaJ1DJKs/TqRkMOvQjvRorHE4pRDLNWLGlRHGUeYIORXs9e5B7OP31E0fmdyb/t0DJ4Q'. + '27bfx3YZzPUIoAAz7IpOD6cuxq0uNumqLfVNDOqXBoZEjnZcqhIPXH4c46+WkdoWOltu3IDDLLLVVR83UVcuPEmmcZZ2/rHoAANG'. + 'GI7KIY1ijoLeEQBVCwIoAHpgY6Hy0aZe7mJ2jeHLKcEhusj6aNKgzr//2Q==' ; + + //========================================================== + // d7-small.jpg + //========================================================== + $this->digits['7'][0]= 658 ; + $this->digits['7'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgEFBwT/xAAuEAABAwIE'. + 'BAQGAwAAAAAAAAABAgMEBREABiExEhMiQSMyUXEHFBclVJFhk9L/xAAXAQADAQAAAAAAAAAAAAAAAAAAAQID/8QAGREBAQEAAwAA'. + 'AAAAAAAAAAAAAAEREiFR/9oADAMBAAIRAxEAPwDXq9mCjZeQ05VZ5ZST4bfEpa3VdglCbqUe+g9MZ5Uq7V8415WXoMSdQ6etgSps'. + '19wpkCMDZKUpv0FZvbi1NzpYasMDLDUbMVXrtQdbeeU23xLWkj5RlLYK0J7anW9gbAjCzkOtsVSUJUdtc6dVZK51UeaFm4LKbhpC'. + 'l7EhIFkDW974GbRI2XorUVls1OTdKAOqUpR0Hc3198GITQ6k+hLwrEpoODiDenRfW23bBicg78JXxPpD0mgVOW5PAivNNpahsPW5'. + '8xxQaSVkboQnhsnYm5OHqDGp1IpsalMKjMsMIC3+XZKbJFth62/QOEfMOZqZXp9JcKZTcGmTky3meSi7xQklI81vMR+sXIz/AEgp'. + 'Q0qPNu6ea8Q2jqtbp8+2w9h/OKORc/cpHjt1dDSHOtLZ4ekHW23bBjj+o9H/AB539aP94MG0+L//2Q==' ; + + //========================================================== + // d3-small.jpg + //========================================================== + $this->digits['3'][0]= 662 ; + $this->digits['3'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwL/xAArEAABBAED'. + 'AwMDBQEAAAAAAAABAgMEBREABhIhMUEiMmETFZEHFkJDUdH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAL/xAAYEQEBAQEBAAAAAAAA'. + 'AAAAAAAAEQExQf/aAAwDAQACEQMRAD8A0vclruBdk3VVLLUNssGRJsZSCtqOjlgJAHvcOD6c4HnOdIbcttw1W5P29cFEhuawqTXS'. + 'VsJjnCMBxKkJJx7goAde+ceJfdNxU0UNlyymyXHi6kxWUNl1S3EnkAEIHX2nv86qtTuZr9Q9+1VhRsOoYpYcgSVyAE/TdewkJxnK'. + 'sBCjkdPGpnOtFMd3PqsXgfOAgD8Y0aX+11H9rDDjn8lr9yj5J+dGqsqxaw6Cc9cQZU4Sp7zTJsIrKlcUEKwhSin1JABI45GUjqOu'. + 'lbOvjbc3Ts9ynjGCy445UuFLYRzbWgrT6fhSCQSMDke+pew2zYVly/d7YchNqkMJZnQpgV9J8IzwWFJyUrAJHYgjvpLbu37G5nR7'. + 'vck5C3YRKYEOEVJZj8kjKypXqWvirjk9h+dB9i4faa89TDZUfKlIyT8k+To10a6KTkpcJ/0vL/7o0TS//9k=' ; + } +} + +class AntiSpam { + + private $iNumber=''; + + function __construct($aNumber='') { + $this->iNumber = $aNumber; + } + + function Rand($aLen) { + $d=''; + for($i=0; $i < $aLen; ++$i) { + $d .= rand(1,9); + } + $this->iNumber = $d; + return $d; + } + + function Stroke() { + + $n=strlen($this->iNumber); + for($i=0; $i < $n; ++$i ) { + if( !is_numeric($this->iNumber[$i]) || $this->iNumber[$i]==0 ) { + return false; + } + } + + $dd = new HandDigits(); + $n = strlen($this->iNumber); + $img = @imagecreatetruecolor($n*$dd->iWidth, $dd->iHeight); + if( $img < 1 ) { + return false; + } + $start=0; + for($i=0; $i < $n; ++$i ) { + $size = $dd->digits[$this->iNumber[$i]][0]; + $dimg = imagecreatefromstring(base64_decode($dd->digits[$this->iNumber[$i]][1])); + imagecopy($img,$dimg,$start,0,0,0,imagesx($dimg), $dd->iHeight); + $start += imagesx($dimg); + } + $resimg = @imagecreatetruecolor($start+4, $dd->iHeight+4); + if( $resimg < 1 ) { + return false; + } + imagecopy($resimg,$img,2,2,0,0,$start, $dd->iHeight); + header("Content-type: image/jpeg"); + imagejpeg($resimg); + return true; + } +} + +?> diff --git a/src/classes/jpgraph/jpgraph_antispam.php b/src/classes/jpgraph/jpgraph_antispam.php new file mode 100644 index 0000000..7998df2 --- /dev/null +++ b/src/classes/jpgraph/jpgraph_antispam.php @@ -0,0 +1,615 @@ +chars['j'][0]= 658 ; + $this->chars['j'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAUGBAf/xAAsEAACAQMDAwMBCQAAAAAAAAAB'. +'AgMEBREAEjEGIUEUUXGBBxMVIiNSYWKC/8QAFgEBAQEAAAAAAAAAAAAAAAAAAwEC/8QAGhEAAwADAQAAAAAAAAAAAAAAAAECERIh'. +'Mv/aAAwDAQACEQMRAD8A6veK2st8zRWSyV1dUBfvHaGVI4hknsS7AFv4AyM57ayWbqeS+11xtT2etttwo4YqhEqnQs5bcAfyk4AZ'. +'SOeD441TKRTyingUBG4/ah8j684+dSFzh/BvtaslejMUu9DPQTDnLx4lQ/ONw1TGBm0jdRWqguEMghEisWilgDmNs4Ze+MEEEH40'. +'aUVFTa7JeLjRXu4GjhmnNbSfqFQVlA3rkckOjH/Q99Glmkl0C/Q06pvsvT9vttXHDF6T1KrWbs5gRgQJM+FDlQxPhjpF1XcVq+qe'. +'jEoKiOecXBqh2TDDYIXLKuP6549xk8auI6aJqV45oknWdNswkAIkGMYIxjGO2NR1F0LZY5qkWqkS1xrM0M8lMSJpY+TGrnJiQ577'. +'cEgeNHhi7D3qC3UN69M8tIakRhgrh9o748+eNGtcCiKjjpkQKlMTEg3ZwoxtHHtgfTRpYXArvp//2Q==' ; + + //========================================================== + // lf-small.jpg + //========================================================== + $this->chars['f'][0]= 633 ; + $this->chars['f'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQFBgcC/8QAKxAAAgEDAwMCBQUAAAAAAAAA'. +'AQIDBBEhAAUGEjFBEyIHFFFhoRUzYnGS/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQP/xAAaEQACAwEBAAAAAAAAAAAAAAAAAQIRMRIh'. +'/9oADAMBAAIRAxEAPwDcnmLoIkiSYsouC3tA++O2lU9WkqVjJ+YdhZLsQI/4/YfQm50kZP0vbmaCSU0SRNIH6sghb9INs3t38dvp'. +'akUuz8x5DwdN5peS1jV1dSipSiVUigIcdQjQ26lIB/c6r3F86SZpE/zCFJaqsihQNhRgdj3Jyfxo0jDSbXHt9Oph9RAoV3qJGltY'. +'HDOxyb/nRpV0D3RXle21m48XraOk3IUSemUaV4g4Zc9ShcDtgff+tQfwvjq34Dtku7buamFqeJKemCCMxKFsEJU+/FrX8d76sEHG'. +'aNItzr4usVNdG3S0rmRYAVwEUmyjyQLZ11x7aF4zs9DQOyzml29I2cLa/pixIHi99DFCtU9dFuLIaijo9qiYPmR2mZmB9thgAHOD'. +'4+mjUrURyrUNMZFEkkIOFuFAbsP9d/OjVIQ6Vh4tP//Z' ; + + //========================================================== + // lb-small.jpg + //========================================================== + $this->chars['b'][0]= 645 ; + $this->chars['b'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAYCAwUH/8QAKxAAAQMDAwMDAwUAAAAAAAAA'. +'AQIDBAAFEQYSIRMxUSJBYQcVI2JxgqHw/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQL/xAAYEQEBAQEBAAAAAAAAAAAAAAAAATERYf/a'. +'AAwDAQACEQMRAD8A6H95mxNYwLXcX+pCuilSLXJ6YSplaUELjqxwe4IJ5PIPamJ2V0bPcS7+NxCX1cHggAnIP+xSd9RyzHh2m7FQ'. +'Q1CvMNQWTjCt+HFD+PB/Y1fI1PL1HFFt0zaGblFdJQ9cJjpZiqPJUlBAKnPcEpGB5NNRKdrOl1NlgiQol4R2w4Sc5VtGf7opZteo'. +'LhdorjUSM5FnQnlR50NeHQysYxtVxlJHIPgjtRRD3xkaghs6juumdHz4+Y7RVPnt59K2mk7W+fcKWsZ7djTXMkW+xMP3GRJjwIEN'. +'HTG/CWx5wPY8AADx2NYk3SL9wukvUjGobnBkORksIbjdMANozgEqSo8qJPGO/wAVO36IsjUmBIfZfuM7epZk3F9UhSSk5O0K9Kcq'. +'8AcU3UzFuhUSBFud6nRXoz96mqmJZWg7m2dqUNhWBwdqQSP1UU5c/FFCn//Z' ; + + //========================================================== + // d6-small.jpg + //========================================================== + $this->chars['6'][0]= 645 ; + $this->chars['6'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAEBAAMBAAAAAAAAAAAAAAAABgMEBwX/xAAvEAABAwMC'. +'BAQEBwAAAAAAAAABAgMEAAURBiESIjFRBxMUQRUWMmFTYnGRkrHC/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFhEBAQEAAAAA'. +'AAAAAAAAAAAAAAER/9oADAMBAAIRAxEAPwDslwiR3oDku8ONttsAvDiVyMcO/ET7ke5/aoOz6k1Vr5htNjW7a7M1yO3NTQU9JUDu'. +'GgrlSn8xyf6p4gXaHJvNps9/mKZtSkGdMjRwpfqAFBLLACRlZUrJONsI2717No1lbZ10kx7XGnRpKWQ/6GVGMfzEJ5VFIVtsOH6e'. +'wyKVhYsia0y22pLThSkJK1uniVgdThOM0ol+StIUhpopIyCFq3H8aUVCwnG3PGe4Rp6fLXJtMdyM0ojcIWvIz3HFnAPfrWTXb6GN'. +'WaLXDwZjVz8pKEfhuIUFg/bAz9sVJ61nt61mxJFslLtq7e5yPqiBT4UDklKw4MDpt+u+9bFiu9riXNu83R+fcr6tohuQ5HQhmK37'. +'paaC8DruScmg6X8KkjZEhbaB9KEyFYSOw26Uqd+e7Qerl5z74DY/1SomP//Z' ; + + //========================================================== + // lx-small.jpg + //========================================================== + $this->chars['x'][0]= 650 ; + $this->chars['x'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABMDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAUHBgj/xAApEAABAwMDAwQCAwAAAAAAAAAB'. +'AgMEBQYRACFBBxIxFCJRgRNxkcHw/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/xAAWEQEBAQAAAAAAAAAAAAAAAAAAEQH/2gAMAwEA'. +'AhEDEQA/AH9t3pKvO14UykVARa/HfAlxlDKXR24V2p3z7RlPwdtMep91uWdRGHWELjuTFFtLvcC4SNznnH+21O7ttiodOq1BvC0E'. +'p9I0lSX2kgqCSklK+5PKCMAng6zV2XRO6u3lSIURtbDRShltlZHa0tW7q/0MeTwnjxq1Jiw2xc9xTLbhSVU5iaXUFfqFFILgJOCd'. +'9Gt3SXabR6REpkL8yo0RpLCFNx1qBCRjOQMHxo0pEr6o3um2LVYpMEpTVqg25lHn08dfcB9kEgfZ1LIFDuawqZRb7aQlLTzqglsg'. +'9wQdveOEqBIB425xqhQuk8qo9UKlPrlRblw2ZBeCSVKW6CcoSrI2AGOT41SKzT4dYtmdS5bIXDZhNoWgbZJ94x8AYT/GkM03oNUc'. +'uKgwqtTZDTMOU0FttqRkoHggnPkEEHRrkJ6t1SlSHYUOc6zHaWrsbQrATk5/vRqK/9k=' ; + + //========================================================== + // d2-small.jpg + //========================================================== + $this->chars['2'][0]= 606 ; + $this->chars['2'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEQMBIgACEQEDEQH/xAAYAAEBAQEBAAAAAAAAAAAAAAAFAAQHAv/EACsQAAEDBAEC'. +'BAYDAAAAAAAAAAIBAwQABQYRIRIxQVFhcQcTFSJSU5GU0f/EABcBAAMBAAAAAAAAAAAAAAAAAAECAwT/xAAZEQACAwEAAAAAAAAA'. +'AAAAAAAAARESUUH/2gAMAwEAAhEDEQA/AOqXm/Q8dxmOL4PPSnCSNFixx6nXnkXgRT3Te17JWbGsveueSyLZdbPItNxOKLzTLjou'. +'gYCSoSoY8ISKSbFeUrzkdlnTL1YshskiErkQnFEZaF8kkdBBVdjyi6RNL5+9F486eS/ECVkcBtDt1vZcho5viS8ZCp9C9tAIAm/F'. +'VoPRU+HRtJ5JVRP1kP0PfwP+1VKrHBMliXG4Nw8VgE4xGkuqk2S1wTUNEVdIvgpL9iL6KtNxY7WOwo9tt0RCitj0sR2uCbFPPzH1'. +'7+6rRuSRcljMBMsUy2tky045KOawZk5xtEFBJEROO3hx61kh2rPCIX3MhsyC4QmfTbC6lH8dq5212qwkiG5H6Y/9R2qm+ofxqqsL'. +'DLZ6f//Z' ; + + //========================================================== + // lm-small.jpg + //========================================================== + $this->chars['m'][0]= 649 ; + $this->chars['m'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGgAAAgMBAQAAAAAAAAAAAAAAAAcDBAUCBv/EAC0QAAICAQMCBAMJAAAAAAAA'. +'AAECAwQRAAUSBiETMVFhB2KhFSIyQVJxgZHB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgED/8QAGREBAQEAAwAAAAAAAAAAAAAAAQAR'. +'EiEx/9oADAMBAAIRAxEAPwB0MI2lIdgI0Cly3kFXLEn2zx1FDdp7rbpbjUtRWKio3hyxOGQllJzkegX66rQ2qW87Zuk9S5FNVmru'. +'iywyBhjDKTkeXfSr+GRfYtq2KAO32b1BGxAZu0dyJ2DKPTxY1wPddVszycUq2Golq8jRWbcnJWwCVGMjz+VQP50atxMtm2ZUOY4l'. +'4qfUnBP0x/Z0amy4jJm10Tt2yddWasFmfaRfdrlG3UcgArnxKzJ+Fu4DqCMkcgNem2DoWav8PLfTm+FPEkuSNTnqueS5bnHIv6CG'. +'LNjJwM99bm67NB1Ht89KSxNXnr2hNDbiUc47K4KyD2GQMfmMjUnS+7vuIktTqPCaaWCqAMMojPFyw8hyYMQBnAwNJHYGXPTsW9VN'. +'jg2zf50W9zk524GAEihuz+xbIOD82jW5TkjtRPZkTkJ+4VgDhQfuj/f3OjUxl1f/2Q==' ; + + //========================================================== + // lt-small.jpg + //========================================================== + $this->chars['t'][0]= 648 ; + $this->chars['t'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQDBQYH/8QAJxAAAQMDAgYDAQEAAAAAAAAA'. +'AQIDBAUGEQASEyExQVFhIjJxFSP/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAP/xAAZEQADAQEBAAAAAAAAAAAAAAAAAREhMUH/2gAM'. +'AwEAAhEDEQA/AO4BLEiEy7uG4IGxxs5IOOx76wd2XYidSp1HoD70240gcNNPbDyI6wQQpaz8E9MczkdhqtbsKYLieDk6WLKmZmmL'. +'Hk7AHVkbkLI+RQc7uRxgkfr1tx2rGu6VbToLVKkhU+kbugGf9WfaknCk5ycaX0zmaa+3JkqvW/CmzojsB9xoF6OoFK0r6HOcEDI0'. +'aefTuKX5ScMdC14HYq8n12zo1DEUcKTGg1Z+hyBwoPBVIiA/VQyOIgedhUCB4WMfXSV3UufVLcTUIqVf26K6mXDbPVRRzKT54iMg'. +'+zjtq6mtsyJjclxpKlUhSXEbkgkqWnBx4+J5e/zU0pZemPvJJQzEPDfQOrwwFY9AZ5eeYPLV6FwhoFYZuigxpkJeIjqAeIoAk9wA'. +'D46EnuD+6Nc1smDNrTlRkxqtMo1vzKhIdYgU9YDqVpISrLhHxSSd21I0aYyqP//Z' ; + + //========================================================== + // li-small.jpg + //========================================================== + $this->chars['i'][0]= 639 ; + $this->chars['i'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABYDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABwAGBP/EACcQAAEEAQMEAgIDAAAAAAAAAAEC'. +'AwQRBQAGEiExQVEHExSBFWFx/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgMB/8QAGBEBAQEBAQAAAAAAAAAAAAAAAAECMRH/2gAMAwEA'. +'AhEDEQA/AE7c+5M9BeRG29t1WUfKFFYW+GvrI7WD3B9g140YD5T36rcErDjbUR6dCBdejsKUpxITXI2FUrooCh70yvxzHyIlMvuK'. +'eVSH7IKEpJoKqu/ahddLryR/aMiO187bsmrWShhp1AZS2XHHrWhNJrzdf7f7GiVcHk3sptmHkJcJ2DIftS2FrKlJPXudWuLGYeQp'. +'t2fmEIckqIZaaKuSGG0lQ4gduRoFRHQ9AOgs2lOJbk9aSUlpjGvAWeSVH2VKq/2dFPw3IjyJe8s281ct3I9UoHJXGiQkD2STrSZ7'. +'Yf8AOl7JTdw5eOCz0jw3+LbYCfA9nz71msb8KMxoTGTw+5srjsipAdDqFBQBIuiOl6KrdYyJMyTCshlw2G3Fr/HiNqNNAqJJUoGl'. +'KND+h47km1bZwsvCbYYjycxIyK1qDv2yEi0hQviK8atKDcy9j//Z' ; + + + //========================================================== + // lp-small.jpg + //========================================================== + $this->chars['p'][0]= 700 ; + $this->chars['p'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGgAAAQUBAAAAAAAAAAAAAAAAAAECBAUGB//EAC8QAAEDAwMCBAMJAAAAAAAA'. +'AAECAwQFESEABhIiMRMVUWEHFEEWIzIzcYGRocH/xAAWAQEBAQAAAAAAAAAAAAAAAAADAgH/xAAcEQACAgIDAAAAAAAAAAAAAAAA'. +'AQIxAxESIUH/2gAMAwEAAhEDEQA/AOh703xG21DMeOyqoVNDjSzERiwU6Ep5qtZNycA97HTF13d33KWtmlt9xwkLl1NkXVxIuQgK'. +'wLj+hqBvel0qmbR8GnR22nJNZiLeeKr8nDIT1OLJucX+uPbWom7iocRpafOac5MX1ALltp/Cbi+cJH++utdh+WVNL3PNdNYpdWgx'. +'Y0qmLZSrwJJcQoOJ5XKlJFu4HbJOjVbt+V5nu7eopNRivqcdhK+bFnWwA1Y2AOcgjvj9dGlxy0g5y0xd+hNXoG24C4obizq3HZUh'. +'YHqtRHD06bG/8a0MbbG1mqekxaBSGmgkrcdcitlLfrckZIz7DUatbeFak0tyRLUwzT5vmiGm0cufEkFBJItfkD+59tKmiO12atFa'. +'eQukO3ejUxgENqTcfnE5WbkHiOnJ76N2IqI1DibabptS+zkZhtp90F2Y0S026EkAFK/qL46cXv65NVZDfxHmVCK4DE2/RX/lRFbA'. +'C5LwAyq2EtpHZI7mxPYDRqoctdESimz/2Q==' ; + + //========================================================== + // le-small.jpg + //========================================================== + $this->chars['e'][0]= 700 ; + $this->chars['e'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABgDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAYEBQcB/8QAKhAAAQMCBAUEAwEAAAAAAAAA'. +'AgEDBAURAAYSIQciMTJBE0JRYRQVFoH/xAAXAQEBAQEAAAAAAAAAAAAAAAAAAgED/8QAGREAAwEBAQAAAAAAAAAAAAAAAAERAjFB'. +'/9oADAMBAAIRAxEAPwDTszvhEYCoS80BTm2bCjQRwdAzVe2yopkpJtpRUVfjEIc4V2oMerByg5Ji30oMyS3GeMunK0upfnu09MdJ'. +'p2scTmWnnGfx6HThktgLfKj7xEOqyr7QBbL41LhBzpxbcOru0LKDLdSnOHoaltNqSC4qWL0x9xbJYum69caczSaHmGmTmpDUYn4l'. +'UiqjkynzAVtwV23Ud+X4Ibpa2DCPkjhfUaRO/p8yzpb+YHhUmhbev6ZEll1lvqK3jt2XrbBgp6HVwsK3THpfEubGSoOUyFMpbJmL'. +'Deh6SgOGKti57EuY6l62JMWdJy7k3hg1LkOozEbVm7suQSkTiKtkEfP1pH664Za/QItccgI4bseTHdNxiXHLQ8yVl7V32XyioqL5'. +'TGc1ng6eYs0idczXUZscBBABWgEhEtfKNuUezwPnBhEuj8X2M21z9BR6NUX211Kk/UKKAjuhkPhL7XVf8vtgw7UPJlEyrDWFSYLb'. +'LBNF6qrzG6t0spEu6+fpL7YMXhUndp//2Q==' ; + + //========================================================== + // la-small.jpg + //========================================================== + $this->chars['a'][0]= 730 ; + $this->chars['a'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABoDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAABgMEBwX/xAAvEAABAwIFAQcCBwAAAAAAAAAB'. +'AgMEBREAEiExQQYHFBUiUXGBE2EyQkNSgpHh/8QAFwEBAQEBAAAAAAAAAAAAAAAAAAMBAv/EABkRAAMBAQEAAAAAAAAAAAAAAAAB'. +'IQIRMf/aAAwDAQACEQMRAD8AfdQ1pxjqZMSn0mRUZRYDaklJCE3OawO2ttTxY4hl07qFMVs1Ku02kpPnRGhsAqz8W9T9wDjozq6o'. +'Q1lDrcZLGVcmUoZg0obpufxK3Ftt9ccqB1GgBcmLSqtVEqOZcr6ARm/kbXHt7DEtc7WTJKTJqEWvRKfLqL9QplSjuPtGVYOJKBrm'. +'t+U+n94WGStZzNypmRWqckUKTbixy6jAfxPxHtCgKqFNlU5huK6pLMndSlegG4J45N8aKmTMKQRBsCNMzwB+RbHWHGEAZlPZX2hx'. +'qZIC34ygZoYUbB50JSkFXFhZR9BrpheR4fIbQ6gvurJ7q02bIQTuAOAN8x40HAxRr3TrNRpBmSHVt1KMlTyJTCsqkKAPlSf28W+c'. +'UGaD1c9HSR1HFUh9tJU45EBcAtcC9+P9wqbg8IAto9o81yputrVGpiUkgHKkqUTZI32+cKm1z1tIUgPBBAKQ4UBQH3uL3xmXSXep'. +'HVDtXStE5K5jlPU7PF3Q41+okJFkjgC+3OuNSYiSzHaLtRcW4UDMpLYSCbakDW3thhum5p//2Q==' ; + + //========================================================== + // d9-small.jpg + //========================================================== + $this->chars['9'][0]= 680 ; + $this->chars['9'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwP/xAArEAABAwMD'. +'AgYBBQAAAAAAAAABAgMEBQYRABIhE1EUIjEzQUIHMlJhcdH/xAAWAQEBAQAAAAAAAAAAAAAAAAACAQD/xAAYEQEAAwEAAAAAAAAA'. +'AAAAAAAAAREhQf/aAAwDAQACEQMRAD8AkK7brF6X7XpMeGoKhFMLEeT4ZUheEhanF4OcZ2pTgDykk92bZpdCsi7aezLjxkIPUZiV'. +'RSCy8hah7EkZ27yM7V+iscal5bE22Lon1qNDmSKROd8Sl+Ix1lMOlIS4HGgQpbStoUCnlJz8HmsXtW3Lst2rmBAelLMRRekOwnYz'. +'Edls9QKKnOVLyk7UgcbzzrdBthqEJJwZbAI4x1U/7o1TaFa9lG36aXaZTy54VrcXUgrzsGdx+T30aNydweqVw1GS87T6Lb86Q4ha'. +'my/IAYjZBx+snKk99oOQMf1AViE65SY348hzFy6hPKnqtKz7DC1lbqyPrvJKUJ7H+M6Wrt3InP7o1brFNp4bCDGhxGAsqz69VSiQ'. +'ORwBxrrQ7itm1ac7Hp0WoGTIc3PSn0pccdcP2WorycfA1RaRHjxosZqOyhtDTSAhCf2gDAGjVHTd9sKSCumynFEZK1tIJUe58/ro'. +'1V1//9k=' ; + + //========================================================== + // d5-small.jpg + //========================================================== + $this->chars['5'][0]= 632 ; + $this->chars['5'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgIFBwT/xAAoEAABAwME'. +'AQQCAwAAAAAAAAABAgMEBQYRABIhIkEUMVFhBxNCgaH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAv/EABcRAQEBAQAAAAAAAAAAAAAA'. +'AAABEUH/2gAMAwEAAhEDEQA/ANGvW4YVOeiRX5b4mv5Sin05IdlupPKdo/j2SO3+6TbPNQvOsTVz33KRT4csR3YUF7Dsh5OSFvug'. +'kqG4FPBxnjxpvvi4KZb1pTpU+QwxUi2Y7ZIAefUk5ATxnB9/gbtL/wCH1UpuhPUlZlMVaQ0mS8zJjqZOPfc2TwpIUonI9tw40R1r'. +'WNGq/wBdJR1XT3lqHBUnGCfkfWjRWs1ve249erQqQYjOtN1FqPUpCXQ4WIzQSsJwT0UpRwQPG0nzqyuNHobjsl9kBuWqoOoXtT1/'. +'WppZcA8lKRj64HxqU+3KpAr6plElRVKef3S4E0K9O8pLXVzKcqSsJAB9wSAca6bSoNXeuA1+5pEV+SGFNU1iKVFqI0Vdx2AJUeoz'. +'8DGlTDwG3CAf3q/pI0ah6MDhLz6U+EpXwPoaNMU//9k=' ; + + //========================================================== + // d1-small.jpg + //========================================================== + $this->chars['1'][0]= 646 ; + $this->chars['1'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEwMBIgACEQEDEQH/xAAZAAADAAMAAAAAAAAAAAAAAAAABQYCBAf/xAApEAACAQMD'. +'AwQBBQAAAAAAAAABAgMEBREABiESMUEHEyJRkSNCYXGB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFxEBAQEBAAAAAAAAAAAA'. +'AAAAAAEREv/aAAwDAQACEQMRAD8A6jdd4WLbstILnc4Uq0VoWpkJknb6IjXLHJUePOlez923fcW4r1SxWlqC2UbdKirQif3Xw3yA'. +'OFAGT09/kO3OmV3a20MFRf6lIYPcpy7yRRAzgxjIy2M8YwcdiBzpX6d22VNvUlTXsFkuwkrKqNSfnK7F8OTzwrAY+l5zoxKskudN'. +'EgQPUT9PBkWF3DH+1GPxo1mLnRoAqF2VRgGOFmX/AAgY/GjRUP6hVMFv2FuFqUvUGrpDFJMBnpdyF5bsAQew7Hxzp6LZNT0yQ1DI'. +'wp0QCFBhD0jCsfLZHxbx5xxpTuvb1+v9PV7Ztk9roLPLCjmSSN3mX5ZwqjCgZX7PfWxDQb2in96pv9qq46aTE0bW4x9ceAWAYPwS'. +'PsYzoixgmheBGjIVcYCnjp/jHjHbRpe1JLn9OnopE/a0ykvjwDx47aNMXqP/2Q==' ; + + //========================================================== + // ll-small.jpg + //========================================================== + $this->chars['l'][0]= 626 ; + $this->chars['l'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAYEBQf/xAArEAACAQIFAwIGAwAAAAAAAAAB'. +'AgMEEQAFBhIhFEFREzEHFSIyYcFxgZH/xAAXAQEAAwAAAAAAAAAAAAAAAAACAAED/8QAGhEAAwEAAwAAAAAAAAAAAAAAAAECMREh'. +'Qf/aAAwDAQACEQMRAD8A15Zfm1VURj1Fp5AqLKv3OARcL4W5Nzx+MLWjdRz5hqXU6TSb6OCr6WghiQbrJ91gOTy1yT5xZ55myZFk'. +'Gb5ozX6Ondm28XYqpQDwu7jEH4c5S2UaDy4xxrLmlUDWzk8XaQ3O49hbj+RiB85HNg8Ee3aqwIqhDuux7G/HHbvzgxEqaWOvy09R'. +'O0o3hjdQoUji20g+fY3wYSM6pJ4Ylr7V+Zz5PSaezHTlTRNWzxySSxt6q1MSkH6AOT2Fu3Aw7RfF/T9DEkLUeawuF2mKSgdWQj2/'. +'q3+fnDZDlqRZzQGaOGcpTOaeR1u8R+ncN3gj94so2jNWHeMNNKzorEX2qp9v3imNPoRE1zpjUtZ09HJmYq5lury0benZeTww23t3'. +'Ivgw+T0yRRyyxIqNfkLcA8jt7YMKcBWn/9k=' ; + + + //========================================================== + // ls-small.jpg + //========================================================== + $this->chars['s'][0]= 701 ; + $this->chars['s'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGgAAAgMBAQAAAAAAAAAAAAAAAAMCBAUGB//EACwQAAEEAQIFAgUFAAAAAAAA'. +'AAECAwQFEQAGEhMUITEiYQcjQVFxFRZCUoH/xAAWAQEBAQAAAAAAAAAAAAAAAAADAgH/xAAZEQADAQEBAAAAAAAAAAAAAAAAAQIR'. +'EiH/2gAMAwEAAhEDEQA/APWZMhmFXSJU+SGmWFiQtAWMJQAnJUr8Z+w/OuQk71uZnMsqnbjy9s8st9UMCQ6kZJdZaIHEkZ/JHceN'. +'N3HtizuY1JLrG48yLBSC9UTFKQiY4nACir+wAOOMEe2rm2bTbzlqtE1MyBuZAPybpw85KSfDRJ4Cg+Pl/wC61hJeGjV31VuuKqwr'. +'LGU+whZZK+Rw+oYJAyj3GjS4dZFpZVkqPLktdfMXNcaU2kBC1BIITkdx6c599GlnvPAa3TL2vNvU76n0063acr3YSLCEjpUpUQtW'. +'Dhf14SMEnOc57aZ8Tegm7dbrEQGZt1PeTDgc1PEW3FeXAvyAkZVkeMDOm2G3f3O7Cl/qEuqkQg4lp6CRxraWfUlRUD24kZA741Ko'. +'2k1HvlT3ri2sLOCgtsyJz6XEtBwZPAgJAGQMHUNPWKqWItsqh0UCFVyLeKhyLHQ2TMdHNVj+RKlAnJyfto1FW2ahgjrq6LYTFjjf'. +'lymUOLdWfJyoHA+gA7AAAaNPE3ysJdLT/9k=' ; + + //========================================================== + // lh-small.jpg + //========================================================== + $this->chars['h'][0]= 677 ; + $this->chars['h'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGgAAAQUBAAAAAAAAAAAAAAAAAAIDBAUGB//EACwQAAIBAwMCBQIHAAAAAAAA'. +'AAECAwQFEQAGEiExExQiQVEVggcyU2GRocH/xAAXAQADAQAAAAAAAAAAAAAAAAAAAwQB/8QAGhEBAQEAAwEAAAAAAAAAAAAAAQAC'. +'AyEyMf/aAAwDAQACEQMRAD8A6DZb95q9bmpK6ieOCzNHJTxmE+NMhQ5fr1fLq3Ejvkak2e7ipiFsqb3R0m4qkPPJRiRXenU9VjKE'. +'5JVcA9R7nWc3/BUbfoKTdO3VRXhpjbZ2D8Rwk6RyZH6chB+46m7i2hDYtgA2ePlV2VkuKysoLzzRnlIScZJZeeevvjtrX7LK2rp7'. +'tTwwJ9WjhILDrTKnIdMEDl2+P80aVdJZb1QW+vgqENLPH4sBCDLIwUgnOf4GjVvDnLgUk79T81voqjb8NnuUx8pVRCiEaYUSuynl'. +'jHU9mOfnOoOx6hqz8PrbNdfEkMUXg1LSM3rKOUywJ7YAJ1ZTWmSpvdvlaVTDSUzJAhH5ZJBgv0x2RSAPlz21WXqoet3ba9nuW8n4'. +'Jr6qTPqnUNxSM/f6mPvxA9zqJnExTbR+h0nkhVu1uE8j0UBRQ9PGxBKFjnkAScdsDp10a0lc7z0tI7Y5YYN+5GAf7GjVXF4Icj3f'. +'/9k=' ; + + + //========================================================== + // ld-small.jpg + //========================================================== + $this->chars['d'][0]= 681 ; + $this->chars['d'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQFBgH/xAAsEAABAwMEAAQFBQAAAAAAAAAB'. +'AgMEBQYRABIhMQcTI0EUMlFhkRgicaGx/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgEA/8QAGBEBAQEBAQAAAAAAAAAAAAAAAAECETH/'. +'2gAMAwEAAhEDEQA/ALUhp6h3W/X63UlypbhCY0WMjLqGzwDtPCfv/WtealNpVInuVBBqCogcdbU36YUkAkJWVHG8YPXBxxzxqPcN'. +'YtWyWnIlUeW05VEOAvrCnnSkftK1H5lKJPHsMDoDUWq+KdrSbIqsalVsImiEtLUZ2MU71bcYJWkhZ/36ayLHhi/IXZVOmzKqp5uU'. +'688hTyjuGVEFJKvoQesD86NL2jGZp1EoLDSmk+ZAQ8d7oPzp3YGesFWMfxo1YGvSzLsT9QExVX8phTlMaFOExAJIBGQjJwCcL+/e'. +'rd+W7GuO0Kw05CQ6+ww69Gfdb2kFIKk7DgEkjgnr86rXRa9HuyP8LV4SH0sIBbWFFDiFEgDaocgdkjo8ccay0qw7ut5nyrcviQqC'. +'slsRKo0HwlODkBRzxj2AGoXTtpzIdQ8MbffUChz4NCPRaClAo9Mn6c7T3o13wytmo0K05VIqkiPJbizFiMWs4CTgnIIHOST796NL'. +'Ia1JX//Z' ; + + //========================================================== + // d8-small.jpg + //========================================================== + $this->chars['8'][0]= 694 ; + $this->chars['8'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AFQMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABgcEBf/EACsQAAEDAwMD'. +'AwMFAAAAAAAAAAECAwQFBhEAEiEUMVEHE0EVYYEiIzJCsf/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/EABcRAQEBAQAAAAAAAAAA'. +'AAAAAAABERL/2gAMAwEAAhEDEQA/AKL6gVVUa0i1T5QjvTprUJMlxW4R9zgQXe/AH+kaWrntqlWjaq7gpcmotXAw82ht9yY4tch8'. +'uAFC0k7VBXPGMY51ruiaue+bThIj+7NbWqS+7HDxajFf6AlB/k44o8ZOABk4xkL0X0tZiojKrlRuGRJjugqldSlKGf6t7BuUQe3J'. +'44xxxrA1a4KVJipLidri8uLHgqOcfjOPxo0o2hdDvS1CmV2Yl6fS5ioipIQR1CAlKkLKR2UUqAI8g6NRSwuuyHab6s1ufLI/Zai7'. +'UBJOxhTS0+6B32pWSFH4CidOdWU0ukLiN1BLr0zG5Sdm3GRvcPhIT858DvjXNrVsSLnm/VIdTXS6tTnFsxZTSN3jchaTwps+O/z9'. +'tcBVq3hIX0tYqlIiQHdy5CqRHKHXEjAOMgBKjnvyRk4xrQa7OiGt1K5biYZL8SoVEpjOqkFsONtJCNwASeCQrn7aNUKnQYtLp7EC'. +'EylmLHQltptPZKQOBo1FzH//2Q==' ; + + //========================================================== + // lz-small.jpg + //========================================================== + $this->chars['z'][0]= 690 ; + $this->chars['z'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABYDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABgAHA//EACsQAAEDAwQBAwIHAAAAAAAAAAEC'. +'AwQFESEABhIxBxMiQVFxCCM0UmGRof/EABYBAQEBAAAAAAAAAAAAAAAAAAECAP/EABgRAAMBAQAAAAAAAAAAAAAAAAABEVEC/9oA'. +'DAMBAAIRAxEAPwBTWfLu1KXXZDbM4uewNvLajlwhaCbBAwDe5uehYd3xm6t6bi3jvulwqc7KgxXZZeYQLNLeF73WRg4HEdgfzrSa'. +'P45pNEkznITDc9ypLShtyWhJDJyXC2qxJHZvjoZOjyVv1v8AESt6FFS4ijxvTLbawEApSccrYHJf0+OtJMQ2rNXk7GZMufJgJjTH'. +'Un9M4qzxT7hyCiThIyRnPXWrRvyLElVBUF6vlhl0lwRYCFKcQhAtyWpVhyWTx+w++rUvp4EWjOvbniUOnVatcS43BYDbJSPZyIBw'. +'ejclIx+3Wa+J63T6DQanuGszI0eZVJJV60p0Jum5GEi6le7l0PjvSjyRsaTvJqI1BqhhR46ksuMrQVJcUSEoUbHNr/7o7C8L7eiz'. +'4lLlyJk2cEqW+6V+m0AE9ISLnsj5+O9UhsFK92bZZqb9SRu9p2c4A0OCEqDbYAJSlJwAVZv3fBvbFrg/462btlhuS1RG5nL8pYkq'. +'KrnsKH06I/rVrQKkf//Z' ; + + //========================================================== + // d4-small.jpg + //========================================================== + $this->chars['4'][0]= 643 ; + $this->chars['4'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABAYHAv/EAC0QAAIBAwQA'. +'BAMJAAAAAAAAAAECAwQFEQAGEiETFDFBUmGBByIjUVNxobHR/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAIB/8QAGBEBAAMBAAAAAAAA'. +'AAAAAAAAAAERIVH/2gAMAwEAAhEDEQA/ANjM00Nxmt1xiWW31CZp5uJwoAAaOQ/n7qfcZHqO5my3q5XX7R6ijiqnNut9u4NyJ4yv'. +'JJyjYr8Xhrn5g599J7x3ulBNU7Zo7dXXXcLQ8kURYi4epYtkALjOePv1nUvbLvV7P3BZm3DR3eh88Kp7pVzBZI6iUhGWRRGWwE44'. +'HX3V+uiL1uHgt+vL/H+aNJQ3CSeCOaFqSaJ1DJKs/TqRkMOvQjvRorHE4pRDLNWLGlRHGUeYIORXs9e5B7OP31E0fmdyb/t0DJ4Q'. +'27bfx3YZzPUIoAAz7IpOD6cuxq0uNumqLfVNDOqXBoZEjnZcqhIPXH4c46+WkdoWOltu3IDDLLLVVR83UVcuPEmmcZZ2/rHoAANG'. +'GI7KIY1ijoLeEQBVCwIoAHpgY6Hy0aZe7mJ2jeHLKcEhusj6aNKgzr//2Q==' ; + + //========================================================== + // lv-small.jpg + //========================================================== + $this->chars['v'][0]= 648 ; + $this->chars['v'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQDBQYH/8QAKBAAAQQBAwMEAgMAAAAAAAAA'. +'AQIDBBEFAAYhEzFBEhQiYQdRFTKB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFxEBAQEBAAAAAAAAAAAAAAAAAAERIf/aAAwD'. +'AQACEQMRAD8A6Ngt1SZ4yrYgrecgTFsFJA9aGwAUrUaF2D2Avjzq6CIjiBPkB9bwQVIkIYIDae/wq+P9N+dY4SGMf+Txlev7KBmY'. +'PoadKRy4zxSgRxaTwO/x09u7KPYnasmHjlsyFZZXt4K23ezjvBpNGgLUrvXfVZyLLbWambiwEbKvvxYAkeotNlIJW2FEJWb7WBda'. +'NSQI0fHYyJjkrjKRDZQwnpQ1vgBIr+w8+a+9GocZr8iKkuY1eXhsKH8U8iZE9BHz6ZHUc48UfSPqzqH3kfeO9kTTDQYGGietpTaO'. +'shyW6AocpHNIrv8AvWzk9BUSdPdYS4BcRlomkhIV6KP0VE39V+tU2wdlRMHtZUB8NuTQ+51X27+Kr46ZPIAFV540D8zeLsJ5LMHa'. +'ubmMBCVJdjx0pRyLoWR4I8aNIQ8BvZMNtMTeUcsptKfc4tC1gAkCyFC+K0aJtf/Z' ; + + //========================================================== + // lk-small.jpg + //========================================================== + $this->chars['k'][0]= 680 ; + $this->chars['k'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAAAAUGBAMH/8QALhAAAQMDAwIEBAcAAAAAAAAA'. +'AQIDBAUREgAGITFBEyIyYQcVUYEUIzNicZHx/8QAFgEBAQEAAAAAAAAAAAAAAAAAAwEE/8QAGxEAAwACAwAAAAAAAAAAAAAAAAEC'. +'AxESMeH/2gAMAwEAAhEDEQA/APVK/V36dU6NSJDTT8esPLiqfK8S2cCoeTkKvZQ6jm2ldSqKqbu+OgMOvSX3m4UBrLnDlbqiefKl'. +'Nzz2x1m+IwNP27CkJQ7JkR6rCkMJbP5jp8S2CPfkgD6H+dJ6Ca0nerr+64rTNSqMYrg+C9mmOwhVpDfsuxSbi97DmybaoZeQ5jTl'. +'PEp18JTIfeW3kq3ly4H26aNZqvTWZsjFcZTsVtSg0G8Rio+vr2vb7g6NLPRnuXy8F+8kl+obUh4KXJdqSJJQnohlkZqJPYBXh3P+'. +'a4b5Hyp6k1bO7sOotPyXkj9NlwFl0ewstJA9ifrqkVSmET4csoS7UTHXFQ+6SQlskKUMb/tH9ddLVUmS7DqdBqD7U6OsqfS46jzl'. +'hQ5bXb1K9Scuybdxo2OTu92dwSZkWn0Sb8viQWyn8Qq5D6ifSLd0BIv7q0arTBRSKPToMZbi2GWylsvLK148Wue/XRrRjxOpT2R2'. +'k9aP/9k=' ; + + //========================================================== + // lr-small.jpg + //========================================================== + $this->chars['r'][0]= 681 ; + $this->chars['r'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABYDASIAAhEBAxEB/8QAGgAAAgIDAAAAAAAAAAAAAAAAAAYCBQMEB//EAC4QAAICAQIFAgMJAQAAAAAA'. +'AAECAwQRBQYAEiExQQdRFGFxEyIyM0JSYoGC8P/EABYBAQEBAAAAAAAAAAAAAAAAAAEAAv/EABcRAQEBAQAAAAAAAAAAAAAAAAAB'. +'EUH/2gAMAwEAAhEDEQA/AOs0ZdETU54Gt1INSmlPJEsyo7J+jlXPUYBPY9c+eE/dO9tY0a7ren6BVrW7VJTZtW5kZkjXkBSIKveQ'. +'gHp0AAJ4w+q2hVdT2Md0h46+saS4mr3EUK0gWTAB+vQj2PboeL/ZVOqmhaZVjkFmxdC6tctt3tM2G5/7bAx4C4+qxiWwd3prWzKe'. +'r3IBAth5OYxozKsgc8y4GTgnJB9uncdTi6tXq2140rRVM13JMEMAVAg7sMdBjJB/18uDgRO9R2Oo6FX2vShkFzURFUq1whIj+8DI'. +'7EdAFjXv7MeNb0kuStsFEmIaajZaos2fy2Q4VGH7SGxn+Rzw9yMLOm/FzRhZazmOTkP4grYyD3B8j2PTyeFfZ+z7G3BeSS8lmprl'. +'2K2qcnK0Z5S8gPjrgAY8cNEWmq7u23pEos6/Zji+Kd0rLLGWwseA3joeZj/w4OET1g0vlmrWV+ydFnkUxSgsvM4V+YYIwfHz6cHB'. +'ZeKZ1//Z' ; + + //========================================================== + // lg-small.jpg + //========================================================== + $this->chars['g'][0]= 655 ; + $this->chars['g'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQCBQYH/8QAJxAAAQQBAwQCAgMAAAAAAAAA'. +'AQIDBBEFAAYhBxIxQRNhcYEiQlH/xAAYAQACAwAAAAAAAAAAAAAAAAACAwABBP/EABkRAAMBAQEAAAAAAAAAAAAAAAABAhEhIv/a'. +'AAwDAQACEQMRAD8AayO4t6bq3hmMHtxyLi4OKeKH5jyASiiQCCQeTRNAeB61FrBb+jTGpLO+BMW24EFMhkhpQru8m7B/H70x09Yi'. +'q3nv/vLfwpnJ7UNkqSRbngf2ofWkpXV7brymC2malLfagurjW0aHk89xPJ9cX9aprURHWbYEaMHHEBfwpv8AnXPk+/8AdGqGJOxO'. +'4YbOSxK4y4boIStUWysgkEmxY54r60aOI8oTV9MHtjJwunPUbO46WWo0HLlD8KY4goboFVoquOVEVwLT963WdnxYfT6ZJyz0JvHm'. +'KvtaSkW4tYNVSqKiTwB+fw5n9sY/cuOXCzDDcluyW3Ckd7V+0n0eNZTH9DdouFalHIOJBUhtDki0pNV3UALo81ehG6IdKjPZ6d47'. +'4ywltanVJvuJI+RQs/sHRqy2r003JhsImEc/CUyhxRZBjKV2oJ8eRXNmufPnRo1WIz3DdNn/2Q==' ; + + //========================================================== + // lc-small.jpg + //========================================================== + $this->chars['c'][0]= 629 ; + $this->chars['c'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAAAAUGBwID/8QALRAAAgICAQIEBAYDAAAAAAAA'. +'AQIDBAURACExBhIiQRMVUWEHMkJScYFykaH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAgP/xAAXEQEBAQEAAAAAAAAAAAAAAAAAATER'. +'/9oADAMBAAIRAxEAPwDcoGkmiT4Q8kWvzuPU38D2/v8A1zwrCFayq1qTaFk2H7aJHt05MeMvENzC4upDWkjW9kJXiricAJCigvJN'. +'IB1IVQT5frrv24twPgunk6a288crbklUSJNNdnSTZ2STHHqOP/Eb17njdZtAoqwEvrEiGVyG117/AG6HhyV8H1sljMldoxXTksGC'. +'zV7M0oaWGQOVeGQ92I6EMR22D11w4LmEPjaOL51iL8ssc9Z69zHtZkYCGGeQK0ez2UEoU39wCeX1S/LLiEt+mPSbMLxsGVv2kEjR'. +'305xkaEV/GTULMUT1LD/AAGh8gIZS2jv+vpybb8NMIb0dVLWYWgiiU0vmMphOj6V0TvQI3rfsON1E6dYjGtisa0F1mAWR2NhG0WZ'. +'3Ls3TqNs5Hc9h23w49NWL9K+Q/VD5T/zhwPH/9k=' ; + + //========================================================== + // d7-small.jpg + //========================================================== + $this->chars['7'][0]= 658 ; + $this->chars['7'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgEFBwT/xAAuEAABAwIE'. +'BAQGAwAAAAAAAAABAgMEBREABiExEhMiQSMyUXEHFBclVJFhk9L/xAAXAQADAQAAAAAAAAAAAAAAAAAAAQID/8QAGREBAQEAAwAA'. +'AAAAAAAAAAAAAAEREiFR/9oADAMBAAIRAxEAPwDXq9mCjZeQ05VZ5ZST4bfEpa3VdglCbqUe+g9MZ5Uq7V8415WXoMSdQ6etgSps'. +'19wpkCMDZKUpv0FZvbi1NzpYasMDLDUbMVXrtQdbeeU23xLWkj5RlLYK0J7anW9gbAjCzkOtsVSUJUdtc6dVZK51UeaFm4LKbhpC'. +'l7EhIFkDW974GbRI2XorUVls1OTdKAOqUpR0Hc3198GITQ6k+hLwrEpoODiDenRfW23bBicg78JXxPpD0mgVOW5PAivNNpahsPW5'. +'8xxQaSVkboQnhsnYm5OHqDGp1IpsalMKjMsMIC3+XZKbJFth62/QOEfMOZqZXp9JcKZTcGmTky3meSi7xQklI81vMR+sXIz/AEgp'. +'Q0qPNu6ea8Q2jqtbp8+2w9h/OKORc/cpHjt1dDSHOtLZ4ekHW23bBjj+o9H/AB539aP94MG0+L//2Q==' ; + + //========================================================== + // ly-small.jpg + //========================================================== + $this->chars['y'][0]= 672 ; + $this->chars['y'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQGBQf/xAArEAABAwMEAQIFBQAAAAAAAAAB'. +'AgMEBREhAAYSEzEHIhQkQVGxQmFxgaH/xAAWAQEBAQAAAAAAAAAAAAAAAAADAQL/xAAeEQEAAgEEAwAAAAAAAAAAAAABABECAxIh'. +'MUGR8P/aAAwDAQACEQMRAD8Ar3tys07dVHohemz5dWQ7fk91MsA3IIRY8rkKFySceTqw3JVV0KhyKw+0C1CQp9aUOFSiAk4AIAvn'. +'76xtz0ioVvbcJ6msx2JtOfZmw1PKI5LQcJNh7UqBKcn6+NRfqPu6s1fYc6GxSJsRfWDUVSGA22ygEckJWSexRNgOP0udXzDKOJ0I'. +'yo62mHm25Sy80l1Z4lSgpQvZRGLgWwPGjTjbchyLH+Ejx22EtJSgO8kki3kADA/nOjWjGzv73CyQZjUWNVp7bNSrj7qJDqflqUlQ'. +'DMds24l3HvcNr3Pi9gME6T9WWVsemdYWswwC2lPta4m5WMA3OdUExCmozUJD6g84ntMjrHIFBTdQz5yLDx/WDNytpwW6nAkViqVe'. +'uvmXdlme6n4dCwlRBKEgA2tj99QG7Ilncp5QqpU31PMsJ6x7A32f6SPxo0hPVCD45oVyKf0MtgeT97/nRrO7UOCFla3tn//Z' ; + + //========================================================== + // d3-small.jpg + //========================================================== + $this->chars['3'][0]= 662 ; + $this->chars['3'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwL/xAArEAABBAED'. +'AwMDBQEAAAAAAAABAgMEBREABhIhMUEiMmETFZEHFkJDUdH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAL/xAAYEQEBAQEBAAAAAAAA'. +'AAAAAAAAEQExQf/aAAwDAQACEQMRAD8A0vclruBdk3VVLLUNssGRJsZSCtqOjlgJAHvcOD6c4HnOdIbcttw1W5P29cFEhuawqTXS'. +'VsJjnCMBxKkJJx7goAde+ceJfdNxU0UNlyymyXHi6kxWUNl1S3EnkAEIHX2nv86qtTuZr9Q9+1VhRsOoYpYcgSVyAE/TdewkJxnK'. +'sBCjkdPGpnOtFMd3PqsXgfOAgD8Y0aX+11H9rDDjn8lr9yj5J+dGqsqxaw6Cc9cQZU4Sp7zTJsIrKlcUEKwhSin1JABI45GUjqOu'. +'lbOvjbc3Ts9ynjGCy445UuFLYRzbWgrT6fhSCQSMDke+pew2zYVly/d7YchNqkMJZnQpgV9J8IzwWFJyUrAJHYgjvpLbu37G5nR7'. +'vck5C3YRKYEOEVJZj8kjKypXqWvirjk9h+dB9i4faa89TDZUfKlIyT8k+To10a6KTkpcJ/0vL/7o0TS//9k=' ; + + //========================================================== + // ln-small.jpg + //========================================================== + $this->chars['n'][0]= 643 ; + $this->chars['n'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGwAAAgEFAAAAAAAAAAAAAAAAAAYCAQMEBQf/xAAtEAACAQMCBAUCBwAAAAAA'. +'AAABAgMEBREAIQYSE0EHIjFRcWGRIzIzQoGCwf/EABYBAQEBAAAAAAAAAAAAAAAAAAMEAP/EABkRAQEBAQEBAAAAAAAAAAAAAAEA'. +'AhEhUf/aAAwDAQACEQMRAD8A6FR3p7v4oV9rlkMQsjL00RyOss0KkFxnDcrc2PbI1NOJKyTjW+W5OmKeA0UEJx5meRZS2/8AUfbS'. +'LVGS1+K16vCzfiR3GmoqqXGyxz06hWPsFlVMfOmq1iNvE69KjBYo3oJMZ3GKeYYPxg/fW+xzZX1FLQyxwSTcpWNceu4G3+aNSmpY'. +'qmQzzwh2k8yhv2r2H23/AJ0aoy+EWh7I1ntacR3PxDtEzhjWy0wkkIwYmanU5GO6sNh7rrU8AVdTceNbhDXxNHUQvS0tZ3DzwxVA'. +'fB7hj59/XJ08cPWaKj4gvlwSQiG7dCboqvLy9NOmQT9SM7ayJrBa6K5V91hjlWorp4JGUOAglRSiMMDb82/vgaBGTpVvtNUVtyJg'. +'5+WNAh5ZCu/r2+dGrgq0pi0DhmlRsSSAfqMd+b6ZyNu3po1Rk1yNBe3/2Q==' ; + + //========================================================== + // lu-small.jpg + //========================================================== + $this->chars['u'][0]= 671 ; + $this->chars['u'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAYDBAUH/8QAJRAAAQQBAwQDAQEAAAAAAAAA'. +'AQIDBBEFAAYhBxMxYRJBURSB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAQAD/8QAGhEBAQEAAwEAAAAAAAAAAAAAAQARITFBAv/aAAwD'. +'AQACEQMRAD8A6dLkQmJzu3WVtHIqjf0duKFNuBr5UTQ45F1R8/XI1PMmsYoJyjhS9iI7BKHeKjkXZVXqhyLHP+rrHeR1pZlx1W1M'. +'wTiW0ukkrS28nn5fV2SPPFfurHUKQhzYG7pLYKEfyBhaSOS7dG/YCki/uvWn3LPDOJrwa4kyEzOYeakqkpC3Hk0bNePQHgDRpchY'. +'leIZwzUWauKtuPctTSUlCAUmrBHIKuAPV/ujQsmHdm7hya43UbbD3ZVElOQJsdTS6IQaQUqBHCk8E2Pocgam6oYwObHy0Zm0oi45'. +'T1KBPdpV2f0pom/1Ws7cmPazu98Ltvcq3VzRHfehz8a4pirFEKRZo8eQT+eCdWYfS/b+WYnxpbuVcDRMdHcyTqg2fiAfiLoi+Rf+'. +'jT7Xc74HtOYnHyUOh8yWUvKeHhy0CiPVUAPoDRrm+OeznTva6lzsyMjCYbbaiNJjJSWElagD5tRpNUSALFeNGoOCH7Bv/9k=' ; + + //========================================================== + // lw-small.jpg + //========================================================== + $this->chars['w'][0]= 673 ; + $this->chars['w'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAYDBAX/xAAtEAACAQMDAgMHBQAAAAAAAAAB'. +'AgMEBREABhIhMRMUQRUiIzJRYZEWNIGx0f/EABYBAQEBAAAAAAAAAAAAAAAAAAABA//EABoRAAICAwAAAAAAAAAAAAAAAAABERIh'. +'MVH/2gAMAwEAAhEDEQA/AHXbV13ZLu6t2/uaa1JijWopVp4XUTKSAXRyc+6ehBGeoPbTSlwpql0K3GneqpZViqUhI5JzGMEZJGeh'. +'GlXfaFILDf7FQzXC426rDLTojs8sLqVkXBGcfKf40twWbdWzZY75R0s90ul3jPtKjVMJDNn4DDp8iEhW+wJ1WZG2KWt3Lv26U1tv'. +'92o7PaYkgYUbqVepYlmUBlIwqnB++O2jTDt/bBtth9jcpvEWNGqalZQryTlmeR8jPct6+mNGmRC4a1U13htzVFItB5nA/cyOUVfp'. +'7oz/ALqitJulYJKuqvFsppHALLFb3cp9FBaXr+O51bq0q6i38KK5PDVAAxSzU6SIpz3Kjjn8jUFoS7uFmut1gq17xLFQ+DxOccj8'. +'Rsn+tVpiyJnqv09YfOXu5AycgZZQEhBZjgDBOOgwO/po0sttWHdNzqLruioa4UwmdaC3kYp4IwSvJlBHKQ4OSe3po0qxM6P/2Q==' ; + + //========================================================== + // lq-small.jpg + //========================================================== + $this->chars['q'][0]= 671 ; + $this->chars['q'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAcDBAUG/8QAKRAAAQQBBAICAQQDAAAAAAAA'. +'AQIDBBEFAAYSIQcxIlETCBQVgSNBYf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAER/9oADAMB'. +'AAIRAxEAPwDT3H5Qz+O3LN2vtrF/y86NYLzzVlAABJITQPv2a/17vXMboz3lDEYWPuafNx7CFrS03+2jpK2bs0CUkUa7pRvrUu63'. +'sr438yv7pLEo4XIK5Kcji0uJUkckm+uQUOVH6GsnyJv7A5vaJwuFdkONLmolgONFH4vioKRXYqyCADXvRMh0yspmZ4jyIEtDTK47'. +'aiA0lQUopBJBI/7X9aNT7amRo228e3a31iO3yUzCcdSPiKAIFdCho0TIswZ7GQlO/hlRxBooih1YXzAoKUkX0LPEBX110dJ7zbuv'. +'AORpO04cIpmxH23FSEIRwKuNnsdk0o31702XhFMKbuRUZJWP8LTQ6HBCuIB+iVWSR2BXuqK93/hDlvGzEphmG3Ml5JpDi1I7TzNA'. +'BYFlPafY+/7LBiv1CYDH4iFDOGySlMR22lFP4wCUpANfL11o1r4bxXlWMNEaE/bqlIbCFl/ANPK5Do/M0VDr2Rf3o0TX/9k=' ; + + + + } +} + +class AntiSpam { + + private $iData=''; + private $iDD=null; + + function __construct($aData='') { + $this->iData = $aData; + $this->iDD = new HandDigits(); + } + + function Set($aData) { + $this->iData = $aData; + } + + function Rand($aLen) { + $d=''; + for($i=0; $i < $aLen; ++$i) { + if( rand(0,9) < 6 ) { + // Digits + $d .= chr( ord('1') + rand(0,8) ); + } + else { + // Letters + do { + $offset = rand(0,25); + } while ( $offset==14 ); + $d .= chr( ord('a') + $offset ); + } + } + $this->iData = $d; + return $d; + } + + function Stroke() { + + $n=strlen($this->iData); + if( $n==0 ) { + return false; + } + + for($i=0; $i < $n; ++$i ) { + if( $this->iData[$i]==='0' || strtolower($this->iData[$i])==='o') { + return false; + } + } + + $img = @imagecreatetruecolor($n*$this->iDD->iWidth, $this->iDD->iHeight); + if( $img < 1 ) { + return false; + } + + $start=0; + for($i=0; $i < $n; ++$i ) { + $dimg = imagecreatefromstring(base64_decode($this->iDD->chars[strtolower($this->iData[$i])][1])); + imagecopy($img,$dimg,$start,0,0,0,imagesx($dimg), $this->iDD->iHeight); + $start += imagesx($dimg); + } + $resimg = @imagecreatetruecolor($start+4, $this->iDD->iHeight+4); + if( $resimg < 1 ) { + return false; + } + + imagecopy($resimg,$img,2,2,0,0,$start, $this->iDD->iHeight); + header("Content-type: image/jpeg"); + imagejpeg($resimg); + return true; + } +} + +?> diff --git a/src/classes/jpgraph/jpgraph_bar.php b/src/classes/jpgraph/jpgraph_bar.php index 10a5ddf..fa4a9ca 100644 --- a/src/classes/jpgraph/jpgraph_bar.php +++ b/src/classes/jpgraph/jpgraph_bar.php @@ -5,7 +5,7 @@ // Created: 2001-01-08 // Ver: $Id: jpgraph_bar.php 1905 2009-10-06 18:00:21Z ljp $ // - // Copyright (c) Aditus Consulting. All rights reserved. + // Copyright (c) Asial Corporation. All rights reserved. //======================================================================== */ @@ -41,6 +41,8 @@ class BarPlot extends Plot { protected $bar_shadow=false; protected $bar_shadow_color="black"; protected $bar_shadow_hsize=3,$bar_shadow_vsize=3; + protected $bar_3d=false; + protected $bar_3d_hsize=3,$bar_3d_vsize=3; //--------------- // CONSTRUCTOR @@ -63,6 +65,14 @@ class BarPlot extends Plot { $this->value->margin += $aVSize; } + function Set3D($aHSize=3,$aVSize=3,$aShow=true) { + $this->bar_3d=$aShow; + $this->bar_3d_vsize=$aVSize; + $this->bar_3d_hsize=$aHSize; + + $this->value->margin += $aVSize; + } + // DEPRECATED use SetYBase instead function SetYMin($aYStartValue) { //die("JpGraph Error: Deprecated function SetYMin. Use SetYBase() instead."); @@ -420,6 +430,7 @@ class BarPlot extends Plot { $img->PopColor(); } +/////////////////////////kokorahen rectangle polygon////////////////////// // Remember value of this bar $val=$this->coords[0][$i]; @@ -463,6 +474,47 @@ class BarPlot extends Plot { } $img->FilledPolygon($sp); $img->PopColor(); + + } elseif( $this->bar_3d && $val != 0) { + // Determine the 3D + + $ssh = $this->bar_3d_hsize; + $ssv = $this->bar_3d_vsize; + + // Create points to create a "upper-right" shadow + if( $val > 0 ) { + $sp1[0]=$pts[6]; $sp1[1]=$pts[7]; + $sp1[2]=$pts[4]; $sp1[3]=$pts[5]; + $sp1[4]=$pts[4]+$ssh; $sp1[5]=$pts[5]-$ssv; + $sp1[6]=$pts[6]+$ssh; $sp1[7]=$pts[7]-$ssv; + + $sp2[0]=$pts[4]; $sp2[1]=$pts[5]; + $sp2[2]=$pts[2]; $sp2[3]=$pts[3]; + $sp2[4]=$pts[2]+$ssh; $sp2[5]=$pts[3]-$ssv; + $sp2[6]=$pts[4]+$ssh; $sp2[7]=$pts[5]-$ssv; + + } + elseif( $val < 0 ) { + $sp1[0]=$pts[4]; $sp1[1]=$pts[5]; + $sp1[2]=$pts[6]; $sp1[3]=$pts[7]; + $sp1[4]=$pts[6]+$ssh; $sp1[5]=$pts[7]-$ssv; + $sp1[6]=$pts[4]+$ssh; $sp1[7]=$pts[5]-$ssv; + + $sp2[0]=$pts[6]; $sp2[1]=$pts[7]; + $sp2[2]=$pts[0]; $sp2[3]=$pts[1]; + $sp2[4]=$pts[0]+$ssh; $sp2[5]=$pts[1]-$ssv; + $sp2[6]=$pts[6]+$ssh; $sp2[7]=$pts[7]-$ssv; + } + + $base_color = $this->fill_color; + + $img->PushColor($base_color . ':0.7'); + $img->FilledPolygon($sp1); + $img->PopColor(); + + $img->PushColor($base_color . ':1.1'); + $img->FilledPolygon($sp2); + $img->PopColor(); } // Stroke the pattern @@ -625,10 +677,11 @@ class BarPlot extends Plot { // Description: Produce grouped bar plots //=================================================== class GroupBarPlot extends BarPlot { - private $plots, $nbrplots=0; + public $plots; + private $nbrplots=0; //--------------- // CONSTRUCTOR - function GroupBarPlot($plots) { + function __construct($plots) { $this->width=0.7; $this->plots = $plots; $this->nbrplots = count($plots); @@ -642,6 +695,9 @@ class GroupBarPlot extends BarPlot { } $this->numpoints = $plots[0]->numpoints; $this->width=0.7; + } + function GroupBarPlot($plots) { + self::__construct($plots); } //--------------- @@ -716,7 +772,8 @@ class GroupBarPlot extends BarPlot { // Description: Produce accumulated bar plots //=================================================== class AccBarPlot extends BarPlot { - private $plots=null,$nbrplots=0; + public $plots=null; + private $nbrplots=0; //--------------- // CONSTRUCTOR function __construct($plots) { diff --git a/src/classes/jpgraph/jpgraph_canvas.php b/src/classes/jpgraph/jpgraph_canvas.php new file mode 100644 index 0000000..f942951 --- /dev/null +++ b/src/classes/jpgraph/jpgraph_canvas.php @@ -0,0 +1,95 @@ +StrokePlotArea(); + } + + // Method description + function Stroke($aStrokeFileName="") { + if( $this->texts != null ) { + for($i=0; $i < count($this->texts); ++$i) { + $this->texts[$i]->Stroke($this->img); + } + } + if( $this->iTables !== null ) { + for($i=0; $i < count($this->iTables); ++$i) { + $this->iTables[$i]->Stroke($this->img); + } + } + $this->StrokeTitles(); + + // If the filename is the predefined value = '_csim_special_' + // we assume that the call to stroke only needs to do enough + // to correctly generate the CSIM maps. + // We use this variable to skip things we don't strictly need + // to do to generate the image map to improve performance + // a best we can. Therefor you will see a lot of tests !$_csim in the + // code below. + $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); + + // We need to know if we have stroked the plot in the + // GetCSIMareas. Otherwise the CSIM hasn't been generated + // and in the case of GetCSIM called before stroke to generate + // CSIM without storing an image to disk GetCSIM must call Stroke. + $this->iHasStroked = true; + + if( !$_csim ) { + + // Should we do any final image transformation + if( $this->iImgTrans ) { + if( !class_exists('ImgTrans',false) ) { + require_once('jpgraph_imgtrans.php'); + } + + $tform = new ImgTrans($this->img->img); + $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, + $this->iImgTransDirection,$this->iImgTransHighQ, + $this->iImgTransMinSize,$this->iImgTransFillColor, + $this->iImgTransBorder); + } + + + // If the filename is given as the special _IMG_HANDLER + // then the image handler is returned and the image is NOT + // streamed back + if( $aStrokeFileName == _IMG_HANDLER ) { + return $this->img->img; + } + else { + // Finally stream the generated picture + $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); + return true; + } + } + } +} // Class + +/* EOF */ +?> diff --git a/src/classes/jpgraph/jpgraph_canvtools.php b/src/classes/jpgraph/jpgraph_canvtools.php new file mode 100644 index 0000000..2290a5b --- /dev/null +++ b/src/classes/jpgraph/jpgraph_canvtools.php @@ -0,0 +1,523 @@ +g = $graph; + $this->w = $graph->img->width; + $this->h = $graph->img->height; + $this->ixmin = $xmin; + $this->ixmax = $xmax; + $this->iymin = $ymin; + $this->iymax = $ymax; + } + + function Set($xmin=0,$xmax=10,$ymin=0,$ymax=10) { + $this->ixmin = $xmin; + $this->ixmax = $xmax; + $this->iymin = $ymin; + $this->iymax = $ymax; + } + + function Get() { + return array($this->ixmin,$this->ixmax,$this->iymin,$this->iymax); + } + + function Translate($x,$y) { + $xp = round(($x-$this->ixmin)/($this->ixmax - $this->ixmin) * $this->w); + $yp = round(($y-$this->iymin)/($this->iymax - $this->iymin) * $this->h); + return array($xp,$yp); + } + + function TranslateX($x) { + $xp = round(($x-$this->ixmin)/($this->ixmax - $this->ixmin) * $this->w); + return $xp; + } + + function TranslateY($y) { + $yp = round(($y-$this->iymin)/($this->iymax - $this->iymin) * $this->h); + return $yp; + } + +} + + +//=================================================== +// CLASS Shape +// Description: Methods to draw shapes on canvas +//=================================================== +class Shape { + private $img,$scale; + + function __construct($aGraph,$scale) { + $this->img = $aGraph->img; + $this->img->SetColor('black'); + $this->scale = $scale; + } + + function SetColor($aColor) { + $this->img->SetColor($aColor); + } + + function Line($x1,$y1,$x2,$y2) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + list($x2,$y2) = $this->scale->Translate($x2,$y2); + $this->img->Line($x1,$y1,$x2,$y2); + } + + function SetLineWeight($aWeight) { + $this->img->SetLineWeight($aWeight); + } + + function Polygon($p,$aClosed=false) { + $n=count($p); + for($i=0; $i < $n; $i+=2 ) { + $p[$i] = $this->scale->TranslateX($p[$i]); + $p[$i+1] = $this->scale->TranslateY($p[$i+1]); + } + $this->img->Polygon($p,$aClosed); + } + + function FilledPolygon($p) { + $n=count($p); + for($i=0; $i < $n; $i+=2 ) { + $p[$i] = $this->scale->TranslateX($p[$i]); + $p[$i+1] = $this->scale->TranslateY($p[$i+1]); + } + $this->img->FilledPolygon($p); + } + + + // Draw a bezier curve with defining points in the $aPnts array + // using $aSteps steps. + // 0=x0, 1=y0 + // 2=x1, 3=y1 + // 4=x2, 5=y2 + // 6=x3, 7=y3 + function Bezier($p,$aSteps=40) { + $x0 = $p[0]; + $y0 = $p[1]; + // Calculate coefficients + $cx = 3*($p[2]-$p[0]); + $bx = 3*($p[4]-$p[2])-$cx; + $ax = $p[6]-$p[0]-$cx-$bx; + $cy = 3*($p[3]-$p[1]); + $by = 3*($p[5]-$p[3])-$cy; + $ay = $p[7]-$p[1]-$cy-$by; + + // Step size + $delta = 1.0/$aSteps; + + $x_old = $x0; + $y_old = $y0; + for($t=$delta; $t<=1.0; $t+=$delta) { + $tt = $t*$t; $ttt=$tt*$t; + $x = $ax*$ttt + $bx*$tt + $cx*$t + $x0; + $y = $ay*$ttt + $by*$tt + $cy*$t + $y0; + $this->Line($x_old,$y_old,$x,$y); + $x_old = $x; + $y_old = $y; + } + $this->Line($x_old,$y_old,$p[6],$p[7]); + } + + function Rectangle($x1,$y1,$x2,$y2) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + list($x2,$y2) = $this->scale->Translate($x2,$y2); + $this->img->Rectangle($x1,$y1,$x2,$y2); + } + + function FilledRectangle($x1,$y1,$x2,$y2) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + list($x2,$y2) = $this->scale->Translate($x2,$y2); + $this->img->FilledRectangle($x1,$y1,$x2,$y2); + } + + function Circle($x1,$y1,$r) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + if( $r >= 0 ) + $r = $this->scale->TranslateX($r); + else + $r = -$r; + $this->img->Circle($x1,$y1,$r); + } + + function FilledCircle($x1,$y1,$r) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + if( $r >= 0 ) + $r = $this->scale->TranslateX($r); + else + $r = -$r; + $this->img->FilledCircle($x1,$y1,$r); + } + + function RoundedRectangle($x1,$y1,$x2,$y2,$r=null) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + list($x2,$y2) = $this->scale->Translate($x2,$y2); + + if( $r == null ) + $r = 5; + elseif( $r >= 0 ) + $r = $this->scale->TranslateX($r); + else + $r = -$r; + $this->img->RoundedRectangle($x1,$y1,$x2,$y2,$r); + } + + function FilledRoundedRectangle($x1,$y1,$x2,$y2,$r=null) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + list($x2,$y2) = $this->scale->Translate($x2,$y2); + + if( $r == null ) + $r = 5; + elseif( $r > 0 ) + $r = $this->scale->TranslateX($r); + else + $r = -$r; + $this->img->FilledRoundedRectangle($x1,$y1,$x2,$y2,$r); + } + + function ShadowRectangle($x1,$y1,$x2,$y2,$fcolor=false,$shadow_width=null,$shadow_color=array(102,102,102)) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + list($x2,$y2) = $this->scale->Translate($x2,$y2); + if( $shadow_width == null ) + $shadow_width=4; + else + $shadow_width=$this->scale->TranslateX($shadow_width); + $this->img->ShadowRectangle($x1,$y1,$x2,$y2,$fcolor,$shadow_width,$shadow_color); + } + + function SetTextAlign($halign,$valign="bottom") { + $this->img->SetTextAlign($halign,$valign="bottom"); + } + + function StrokeText($x1,$y1,$txt,$dir=0,$paragraph_align="left") { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + $this->img->StrokeText($x1,$y1,$txt,$dir,$paragraph_align); + } + + // A rounded rectangle where one of the corner has been moved "into" the + // rectangle 'iw' width and 'ih' height. Corners: + // 0=Top left, 1=top right, 2=bottom right, 3=bottom left + function IndentedRectangle($xt,$yt,$w,$h,$iw=0,$ih=0,$aCorner=3,$aFillColor="",$r=4) { + + list($xt,$yt) = $this->scale->Translate($xt,$yt); + list($w,$h) = $this->scale->Translate($w,$h); + list($iw,$ih) = $this->scale->Translate($iw,$ih); + + $xr = $xt + $w - 0; + $yl = $yt + $h - 0; + + switch( $aCorner ) { + case 0: // Upper left + + // Bottom line, left & right arc + $this->img->Line($xt+$r,$yl,$xr-$r,$yl); + $this->img->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); + $this->img->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); + + // Right line, Top right arc + $this->img->Line($xr,$yt+$r,$xr,$yl-$r); + $this->img->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); + + // Top line, Top left arc + $this->img->Line($xt+$iw+$r,$yt,$xr-$r,$yt); + $this->img->Arc($xt+$iw+$r,$yt+$r,$r*2,$r*2,180,270); + + // Left line + $this->img->Line($xt,$yt+$ih+$r,$xt,$yl-$r); + + // Indent horizontal, Lower left arc + $this->img->Line($xt+$r,$yt+$ih,$xt+$iw-$r,$yt+$ih); + $this->img->Arc($xt+$r,$yt+$ih+$r,$r*2,$r*2,180,270); + + // Indent vertical, Indent arc + $this->img->Line($xt+$iw,$yt+$r,$xt+$iw,$yt+$ih-$r); + $this->img->Arc($xt+$iw-$r,$yt+$ih-$r,$r*2,$r*2,0,90); + + if( $aFillColor != '' ) { + $bc = $this->img->current_color_name; + $this->img->PushColor($aFillColor); + $this->img->FillToBorder($xr-$r,$yl-$r,$bc); + $this->img->PopColor(); + } + + break; + + case 1: // Upper right + + // Bottom line, left & right arc + $this->img->Line($xt+$r,$yl,$xr-$r,$yl); + $this->img->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); + $this->img->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); + + // Left line, Top left arc + $this->img->Line($xt,$yt+$r,$xt,$yl-$r); + $this->img->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); + + // Top line, Top right arc + $this->img->Line($xt+$r,$yt,$xr-$iw-$r,$yt); + $this->img->Arc($xr-$iw-$r,$yt+$r,$r*2,$r*2,270,360); + + // Right line + $this->img->Line($xr,$yt+$ih+$r,$xr,$yl-$r); + + // Indent horizontal, Lower right arc + $this->img->Line($xr-$iw+$r,$yt+$ih,$xr-$r,$yt+$ih); + $this->img->Arc($xr-$r,$yt+$ih+$r,$r*2,$r*2,270,360); + + // Indent vertical, Indent arc + $this->img->Line($xr-$iw,$yt+$r,$xr-$iw,$yt+$ih-$r); + $this->img->Arc($xr-$iw+$r,$yt+$ih-$r,$r*2,$r*2,90,180); + + if( $aFillColor != '' ) { + $bc = $this->img->current_color_name; + $this->img->PushColor($aFillColor); + $this->img->FillToBorder($xt+$r,$yl-$r,$bc); + $this->img->PopColor(); + } + + break; + + case 2: // Lower right + // Top line, Top left & Top right arc + $this->img->Line($xt+$r,$yt,$xr-$r,$yt); + $this->img->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); + $this->img->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); + + // Left line, Bottom left arc + $this->img->Line($xt,$yt+$r,$xt,$yl-$r); + $this->img->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); + + // Bottom line, Bottom right arc + $this->img->Line($xt+$r,$yl,$xr-$iw-$r,$yl); + $this->img->Arc($xr-$iw-$r,$yl-$r,$r*2,$r*2,0,90); + + // Right line + $this->img->Line($xr,$yt+$r,$xr,$yl-$ih-$r); + + // Indent horizontal, Lower right arc + $this->img->Line($xr-$r,$yl-$ih,$xr-$iw+$r,$yl-$ih); + $this->img->Arc($xr-$r,$yl-$ih-$r,$r*2,$r*2,0,90); + + // Indent vertical, Indent arc + $this->img->Line($xr-$iw,$yl-$r,$xr-$iw,$yl-$ih+$r); + $this->img->Arc($xr-$iw+$r,$yl-$ih+$r,$r*2,$r*2,180,270); + + if( $aFillColor != '' ) { + $bc = $this->img->current_color_name; + $this->img->PushColor($aFillColor); + $this->img->FillToBorder($xt+$r,$yt+$r,$bc); + $this->img->PopColor(); + } + + break; + + case 3: // Lower left + // Top line, Top left & Top right arc + $this->img->Line($xt+$r,$yt,$xr-$r,$yt); + $this->img->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); + $this->img->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); + + // Right line, Bottom right arc + $this->img->Line($xr,$yt+$r,$xr,$yl-$r); + $this->img->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); + + // Bottom line, Bottom left arc + $this->img->Line($xt+$iw+$r,$yl,$xr-$r,$yl); + $this->img->Arc($xt+$iw+$r,$yl-$r,$r*2,$r*2,90,180); + + // Left line + $this->img->Line($xt,$yt+$r,$xt,$yl-$ih-$r); + + // Indent horizontal, Lower left arc + $this->img->Line($xt+$r,$yl-$ih,$xt+$iw-$r,$yl-$ih); + $this->img->Arc($xt+$r,$yl-$ih-$r,$r*2,$r*2,90,180); + + // Indent vertical, Indent arc + $this->img->Line($xt+$iw,$yl-$ih+$r,$xt+$iw,$yl-$r); + $this->img->Arc($xt+$iw-$r,$yl-$ih+$r,$r*2,$r*2,270,360); + + if( $aFillColor != '' ) { + $bc = $this->img->current_color_name; + $this->img->PushColor($aFillColor); + $this->img->FillToBorder($xr-$r,$yt+$r,$bc); + $this->img->PopColor(); + } + + break; + } + } +} + + +//=================================================== +// CLASS RectangleText +// Description: Draws a text paragraph inside a +// rounded, possible filled, rectangle. +//=================================================== +class CanvasRectangleText { + private $ix,$iy,$iw,$ih,$ir=4; + private $iTxt,$iColor='black',$iFillColor='',$iFontColor='black'; + private $iParaAlign='center'; + private $iAutoBoxMargin=5; + private $iShadowWidth=3,$iShadowColor=''; + + function __construct($aTxt='',$xl=0,$yt=0,$w=0,$h=0) { + $this->iTxt = new Text($aTxt); + $this->ix = $xl; + $this->iy = $yt; + $this->iw = $w; + $this->ih = $h; + } + + function SetShadow($aColor='gray',$aWidth=3) { + $this->iShadowColor = $aColor; + $this->iShadowWidth = $aWidth; + } + + function SetFont($FontFam,$aFontStyle,$aFontSize=12) { + $this->iTxt->SetFont($FontFam,$aFontStyle,$aFontSize); + } + + function SetTxt($aTxt) { + $this->iTxt->Set($aTxt); + } + + function ParagraphAlign($aParaAlign) { + $this->iParaAlign = $aParaAlign; + } + + function SetFillColor($aFillColor) { + $this->iFillColor = $aFillColor; + } + + function SetAutoMargin($aMargin) { + $this->iAutoBoxMargin=$aMargin; + } + + function SetColor($aColor) { + $this->iColor = $aColor; + } + + function SetFontColor($aColor) { + $this->iFontColor = $aColor; + } + + function SetPos($xl=0,$yt=0,$w=0,$h=0) { + $this->ix = $xl; + $this->iy = $yt; + $this->iw = $w; + $this->ih = $h; + } + + function Pos($xl=0,$yt=0,$w=0,$h=0) { + $this->ix = $xl; + $this->iy = $yt; + $this->iw = $w; + $this->ih = $h; + } + + function Set($aTxt,$xl,$yt,$w=0,$h=0) { + $this->iTxt->Set($aTxt); + $this->ix = $xl; + $this->iy = $yt; + $this->iw = $w; + $this->ih = $h; + } + + function SetCornerRadius($aRad=5) { + $this->ir = $aRad; + } + + function Stroke($aImg,$scale) { + + // If coordinates are specifed as negative this means we should + // treat them as abolsute (pixels) coordinates + if( $this->ix > 0 ) { + $this->ix = $scale->TranslateX($this->ix) ; + } + else { + $this->ix = -$this->ix; + } + + if( $this->iy > 0 ) { + $this->iy = $scale->TranslateY($this->iy) ; + } + else { + $this->iy = -$this->iy; + } + + list($this->iw,$this->ih) = $scale->Translate($this->iw,$this->ih) ; + + if( $this->iw == 0 ) + $this->iw = round($this->iTxt->GetWidth($aImg) + $this->iAutoBoxMargin); + if( $this->ih == 0 ) { + $this->ih = round($this->iTxt->GetTextHeight($aImg) + $this->iAutoBoxMargin); + } + + if( $this->iShadowColor != '' ) { + $aImg->PushColor($this->iShadowColor); + $aImg->FilledRoundedRectangle($this->ix+$this->iShadowWidth, + $this->iy+$this->iShadowWidth, + $this->ix+$this->iw-1+$this->iShadowWidth, + $this->iy+$this->ih-1+$this->iShadowWidth, + $this->ir); + $aImg->PopColor(); + } + + if( $this->iFillColor != '' ) { + $aImg->PushColor($this->iFillColor); + $aImg->FilledRoundedRectangle($this->ix,$this->iy, + $this->ix+$this->iw-1, + $this->iy+$this->ih-1, + $this->ir); + $aImg->PopColor(); + } + + if( $this->iColor != '' ) { + $aImg->PushColor($this->iColor); + $aImg->RoundedRectangle($this->ix,$this->iy, + $this->ix+$this->iw-1, + $this->iy+$this->ih-1, + $this->ir); + $aImg->PopColor(); + } + + $this->iTxt->Align('center','center'); + $this->iTxt->ParagraphAlign($this->iParaAlign); + $this->iTxt->SetColor($this->iFontColor); + $this->iTxt->Stroke($aImg, $this->ix+$this->iw/2, $this->iy+$this->ih/2); + + return array($this->iw, $this->ih); + + } + +} + + +?> diff --git a/src/classes/jpgraph/jpgraph_contour.php b/src/classes/jpgraph/jpgraph_contour.php new file mode 100644 index 0000000..760989e --- /dev/null +++ b/src/classes/jpgraph/jpgraph_contour.php @@ -0,0 +1,587 @@ +nbrRows = count($aMatrix); + $this->nbrCols = count($aMatrix[0]); + $this->dataPoints = $aMatrix; + + if( is_array($aIsobars) ) { + // use the isobar values supplied + $this->nbrIsobars = count($aIsobars); + $this->isobarValues = $aIsobars; + } + else { + // Determine the isobar values automatically + $this->nbrIsobars = $aIsobars; + list($min,$max) = $this->getMinMaxVal(); + $stepSize = ($max-$min) / $aIsobars ; + $isobar = $min+$stepSize/2; + for ($i = 0; $i < $aIsobars; $i++) { + $this->isobarValues[$i] = $isobar; + $isobar += $stepSize; + } + } + + if( $aColors !== null && count($aColors) > 0 ) { + + if( !is_array($aColors) ) { + JpGraphError::RaiseL(28001); + //'Third argument to Contour must be an array of colors.' + } + + if( count($aColors) != count($this->isobarValues) ) { + JpGraphError::RaiseL(28002); + //'Number of colors must equal the number of isobar lines specified'; + } + + $this->isobarColors = $aColors; + } + } + + /** + * Flip the plot around the Y-coordinate. This has the same affect as flipping the input + * data matrice + * + * @param $aFlg If true the the vertice in input data matrice position (0,0) corresponds to the top left + * corner of teh plot otherwise it will correspond to the bottom left corner (a horizontal flip) + */ + function SetInvert($aFlg=true) { + $this->invert = $aFlg; + } + + /** + * Find the min and max values in the data matrice + * + * @return array(min_value,max_value) + */ + function getMinMaxVal() { + $min = $this->dataPoints[0][0]; + $max = $this->dataPoints[0][0]; + for ($i = 0; $i < $this->nbrRows; $i++) { + if( ($mi=min($this->dataPoints[$i])) < $min ) $min = $mi; + if( ($ma=max($this->dataPoints[$i])) > $max ) $max = $ma; + } + return array($min,$max); + } + + /** + * Reset the two matrices that keeps track on where the isobars crosses the + * horizontal and vertical edges + */ + function resetEdgeMatrices() { + for ($k = 0; $k < 2; $k++) { + for ($i = 0; $i <= $this->nbrRows; $i++) { + for ($j = 0; $j <= $this->nbrCols; $j++) { + $this->edges[$k][$i][$j] = false; + } + } + } + } + + /** + * Determine if the specified isobar crosses the horizontal edge specified by its row and column + * + * @param $aRow Row index of edge to be checked + * @param $aCol Col index of edge to be checked + * @param $aIsobar Isobar value + * @return true if the isobar is crossing this edge + */ + function isobarHCrossing($aRow,$aCol,$aIsobar) { + + if( $aCol >= $this->nbrCols-1 ) { + JpGraphError::RaiseL(28003,$aCol); + //'ContourPlot Internal Error: isobarHCrossing: Coloumn index too large (%d)' + } + if( $aRow >= $this->nbrRows ) { + JpGraphError::RaiseL(28004,$aRow); + //'ContourPlot Internal Error: isobarHCrossing: Row index too large (%d)' + } + + $v1 = $this->dataPoints[$aRow][$aCol]; + $v2 = $this->dataPoints[$aRow][$aCol+1]; + + return ($aIsobar-$v1)*($aIsobar-$v2) < 0 ; + + } + + /** + * Determine if the specified isobar crosses the vertical edge specified by its row and column + * + * @param $aRow Row index of edge to be checked + * @param $aCol Col index of edge to be checked + * @param $aIsobar Isobar value + * @return true if the isobar is crossing this edge + */ + function isobarVCrossing($aRow,$aCol,$aIsobar) { + + if( $aRow >= $this->nbrRows-1) { + JpGraphError::RaiseL(28005,$aRow); + //'isobarVCrossing: Row index too large + } + if( $aCol >= $this->nbrCols ) { + JpGraphError::RaiseL(28006,$aCol); + //'isobarVCrossing: Col index too large + } + + $v1 = $this->dataPoints[$aRow][$aCol]; + $v2 = $this->dataPoints[$aRow+1][$aCol]; + + return ($aIsobar-$v1)*($aIsobar-$v2) < 0 ; + + } + + /** + * Determine all edges, horizontal and vertical that the specified isobar crosses. The crossings + * are recorded in the two edge matrices. + * + * @param $aIsobar The value of the isobar to be checked + */ + function determineIsobarEdgeCrossings($aIsobar) { + + $ib = $this->isobarValues[$aIsobar]; + + for ($i = 0; $i < $this->nbrRows-1; $i++) { + for ($j = 0; $j < $this->nbrCols-1; $j++) { + $this->edges[HORIZ_EDGE][$i][$j] = $this->isobarHCrossing($i,$j,$ib); + $this->edges[VERT_EDGE][$i][$j] = $this->isobarVCrossing($i,$j,$ib); + } + } + + // We now have the bottom and rightmost edges unsearched + for ($i = 0; $i < $this->nbrRows-1; $i++) { + $this->edges[VERT_EDGE][$i][$j] = $this->isobarVCrossing($i,$this->nbrCols-1,$ib); + } + for ($j = 0; $j < $this->nbrCols-1; $j++) { + $this->edges[HORIZ_EDGE][$i][$j] = $this->isobarHCrossing($this->nbrRows-1,$j,$ib); + } + + } + + /** + * Return the normalized coordinates for the crossing of the specified edge with the specified + * isobar- The crossing is simpy detrmined with a linear interpolation between the two vertices + * on each side of the edge and the value of the isobar + * + * @param $aRow Row of edge + * @param $aCol Column of edge + * @param $aEdgeDir Determine if this is a horizontal or vertical edge + * @param $ib The isobar value + * @return unknown_type + */ + function getCrossingCoord($aRow,$aCol,$aEdgeDir,$aIsobarVal) { + + // In order to avoid numerical problem when two vertices are very close + // we have to check and avoid dividing by close to zero denumerator. + if( $aEdgeDir == HORIZ_EDGE ) { + $d = abs($this->dataPoints[$aRow][$aCol] - $this->dataPoints[$aRow][$aCol+1]); + if( $d > 0.001 ) { + $xcoord = $aCol + abs($aIsobarVal - $this->dataPoints[$aRow][$aCol]) / $d; + } + else { + $xcoord = $aCol; + } + $ycoord = $aRow; + } + else { + $d = abs($this->dataPoints[$aRow][$aCol] - $this->dataPoints[$aRow+1][$aCol]); + if( $d > 0.001 ) { + $ycoord = $aRow + abs($aIsobarVal - $this->dataPoints[$aRow][$aCol]) / $d; + } + else { + $ycoord = $aRow; + } + $xcoord = $aCol; + } + if( $this->invert ) { + $ycoord = $this->nbrRows-1 - $ycoord; + } + return array($xcoord,$ycoord); + + } + + /** + * In order to avoid all kinds of unpleasent extra checks and complex boundary + * controls for the degenerated case where the contour levels exactly crosses + * one of the vertices we add a very small delta (0.1%) to the data point value. + * This has no visible affect but it makes the code sooooo much cleaner. + * + */ + function adjustDataPointValues() { + + $ni = count($this->isobarValues); + for ($k = 0; $k < $ni; $k++) { + $ib = $this->isobarValues[$k]; + for ($row = 0 ; $row < $this->nbrRows-1; ++$row) { + for ($col = 0 ; $col < $this->nbrCols-1; ++$col ) { + if( abs($this->dataPoints[$row][$col] - $ib) < 0.0001 ) { + $this->dataPoints[$row][$col] += $this->dataPoints[$row][$col]*0.001; + } + } + } + } + + } + + /** + * @param $aFlg + * @param $aBW + * @return unknown_type + */ + function UseHighContrastColor($aFlg=true,$aBW=false) { + $this->highcontrast = $aFlg; + $this->highcontrastbw = $aBW; + } + + /** + * Calculate suitable colors for each defined isobar + * + */ + function CalculateColors() { + if ( $this->highcontrast ) { + if ( $this->highcontrastbw ) { + for ($ib = 0; $ib < $this->nbrIsobars; $ib++) { + $this->isobarColors[$ib] = 'black'; + } + } + else { + // Use only blue/red scale + $step = round(255/($this->nbrIsobars-1)); + for ($ib = 0; $ib < $this->nbrIsobars; $ib++) { + $this->isobarColors[$ib] = array($ib*$step, 50, 255-$ib*$step); + } + } + } + else { + $n = $this->nbrIsobars; + $v = 0; $step = 1 / ($this->nbrIsobars-1); + for ($ib = 0; $ib < $this->nbrIsobars; $ib++) { + $this->isobarColors[$ib] = RGB::GetSpectrum($v); + $v += $step; + } + } + } + + /** + * This is where the main work is done. For each isobar the crossing of the edges are determined + * and then each cell is analyzed to find the 0, 2 or 4 crossings. Then the normalized coordinate + * for the crossings are determined and pushed on to the isobar stack. When the method is finished + * the $isobarCoord will hold one arrayfor each isobar where all the line segments that makes + * up the contour plot are stored. + * + * @return array( $isobarCoord, $isobarValues, $isobarColors ) + */ + function getIsobars() { + + $this->adjustDataPointValues(); + + for ($isobar = 0; $isobar < $this->nbrIsobars; $isobar++) { + + $ib = $this->isobarValues[$isobar]; + $this->resetEdgeMatrices(); + $this->determineIsobarEdgeCrossings($isobar); + $this->isobarCoord[$isobar] = array(); + + $ncoord = 0; + + for ($row = 0 ; $row < $this->nbrRows-1; ++$row) { + for ($col = 0 ; $col < $this->nbrCols-1; ++$col ) { + + // Find out how many crossings around the edges + $n = 0; + if ( $this->edges[HORIZ_EDGE][$row][$col] ) $neigh[$n++] = array($row, $col, HORIZ_EDGE); + if ( $this->edges[HORIZ_EDGE][$row+1][$col] ) $neigh[$n++] = array($row+1,$col, HORIZ_EDGE); + if ( $this->edges[VERT_EDGE][$row][$col] ) $neigh[$n++] = array($row, $col, VERT_EDGE); + if ( $this->edges[VERT_EDGE][$row][$col+1] ) $neigh[$n++] = array($row, $col+1,VERT_EDGE); + + if ( $n == 2 ) { + $n1=0; $n2=1; + $this->isobarCoord[$isobar][$ncoord++] = array( + $this->getCrossingCoord($neigh[$n1][0],$neigh[$n1][1],$neigh[$n1][2],$ib), + $this->getCrossingCoord($neigh[$n2][0],$neigh[$n2][1],$neigh[$n2][2],$ib) ); + } + elseif ( $n == 4 ) { + // We must determine how to connect the edges either northwest->southeast or + // northeast->southwest. We do that by calculating the imaginary middle value of + // the cell by averaging the for corners. This will compared with the value of the + // top left corner will help determine the orientation of the ridge/creek + $midval = ($this->dataPoints[$row][$col]+$this->dataPoints[$row][$col+1]+$this->dataPoints[$row+1][$col]+$this->dataPoints[$row+1][$col+1])/4; + $v = $this->dataPoints[$row][$col]; + if( $midval == $ib ) { + // Orientation "+" + $n1=0; $n2=1; $n3=2; $n4=3; + } elseif ( ($midval > $ib && $v > $ib) || ($midval < $ib && $v < $ib) ) { + // Orientation of ridge/valley = "\" + $n1=0; $n2=3; $n3=2; $n4=1; + } elseif ( ($midval > $ib && $v < $ib) || ($midval < $ib && $v > $ib) ) { + // Orientation of ridge/valley = "/" + $n1=0; $n2=2; $n3=3; $n4=1; + } + + $this->isobarCoord[$isobar][$ncoord++] = array( + $this->getCrossingCoord($neigh[$n1][0],$neigh[$n1][1],$neigh[$n1][2],$ib), + $this->getCrossingCoord($neigh[$n2][0],$neigh[$n2][1],$neigh[$n2][2],$ib) ); + + $this->isobarCoord[$isobar][$ncoord++] = array( + $this->getCrossingCoord($neigh[$n3][0],$neigh[$n3][1],$neigh[$n3][2],$ib), + $this->getCrossingCoord($neigh[$n4][0],$neigh[$n4][1],$neigh[$n4][2],$ib) ); + + } + } + } + } + + if( count($this->isobarColors) == 0 ) { + // No manually specified colors. Calculate them automatically. + $this->CalculateColors(); + } + return array( $this->isobarCoord, $this->isobarValues, $this->isobarColors ); + } +} + + +/** + * This class represent a plotting of a contour outline of data given as a X-Y matrice + * + */ +class ContourPlot extends Plot { + + private $contour, $contourCoord, $contourVal, $contourColor; + private $nbrCountours = 0 ; + private $dataMatrix = array(); + private $invertLegend = false; + private $interpFactor = 1; + private $flipData = false; + private $isobar = 10; + private $showLegend = false; + private $highcontrast = false, $highcontrastbw = false; + private $manualIsobarColors = array(); + + /** + * Construct a contour plotting algorithm. The end result of the algorithm is a sequence of + * line segments for each isobar given as two vertices. + * + * @param $aDataMatrix The Z-data to be used + * @param $aIsobar A mixed variable, if it is an integer then this specified the number of isobars to use. + * The values of the isobars are automatically detrmined to be equ-spaced between the min/max value of the + * data. If it is an array then it explicetely gives the isobar values + * @param $aInvert By default the matrice with row index 0 corresponds to Y-value 0, i.e. in the bottom of + * the plot. If this argument is true then the row with the highest index in the matrice corresponds to + * Y-value 0. In affect flipping the matrice around an imaginary horizontal axis. + * @param $aHighContrast Use high contrast colors (blue/red:ish) + * @param $aHighContrastBW Use only black colors for contours + * @return an instance of the contour plot algorithm + */ + function __construct($aDataMatrix, $aIsobar=10, $aFactor=1, $aInvert=false, $aIsobarColors=array()) { + + $this->dataMatrix = $aDataMatrix; + $this->flipData = $aInvert; + $this->isobar = $aIsobar; + $this->interpFactor = $aFactor; + + if ( $this->interpFactor > 1 ) { + + if( $this->interpFactor > 5 ) { + JpGraphError::RaiseL(28007);// ContourPlot interpolation factor is too large (>5) + } + + $ip = new MeshInterpolate(); + $this->dataMatrix = $ip->Linear($this->dataMatrix, $this->interpFactor); + } + + $this->contour = new Contour($this->dataMatrix,$this->isobar,$aIsobarColors); + + if( is_array($aIsobar) ) + $this->nbrContours = count($aIsobar); + else + $this->nbrContours = $aIsobar; + } + + + /** + * Flipe the data around the center + * + * @param $aFlg + * + */ + function SetInvert($aFlg=true) { + $this->flipData = $aFlg; + } + + /** + * Set the colors for the isobar lines + * + * @param $aColorArray + * + */ + function SetIsobarColors($aColorArray) { + $this->manualIsobarColors = $aColorArray; + } + + /** + * Show the legend + * + * @param $aFlg true if the legend should be shown + * + */ + function ShowLegend($aFlg=true) { + $this->showLegend = $aFlg; + } + + + /** + * @param $aFlg true if the legend should start with the lowest isobar on top + * @return unknown_type + */ + function Invertlegend($aFlg=true) { + $this->invertLegend = $aFlg; + } + + /* Internal method. Give the min value to be used for the scaling + * + */ + function Min() { + return array(0,0); + } + + /* Internal method. Give the max value to be used for the scaling + * + */ + function Max() { + return array(count($this->dataMatrix[0])-1,count($this->dataMatrix)-1); + } + + /** + * Internal ramewrok method to setup the legend to be used for this plot. + * @param $aGraph The parent graph class + */ + function Legend($aGraph) { + + if( ! $this->showLegend ) + return; + + if( $this->invertLegend ) { + for ($i = 0; $i < $this->nbrContours; $i++) { + $aGraph->legend->Add(sprintf('%.1f',$this->contourVal[$i]), $this->contourColor[$i]); + } + } + else { + for ($i = $this->nbrContours-1; $i >= 0 ; $i--) { + $aGraph->legend->Add(sprintf('%.1f',$this->contourVal[$i]), $this->contourColor[$i]); + } + } + } + + + /** + * Framework function which gets called before the Stroke() method is called + * + * @see Plot#PreScaleSetup($aGraph) + * + */ + function PreScaleSetup($aGraph) { + $xn = count($this->dataMatrix[0])-1; + $yn = count($this->dataMatrix)-1; + + $aGraph->xaxis->scale->Update($aGraph->img,0,$xn); + $aGraph->yaxis->scale->Update($aGraph->img,0,$yn); + + $this->contour->SetInvert($this->flipData); + list($this->contourCoord,$this->contourVal,$this->contourColor) = $this->contour->getIsobars(); + } + + /** + * Use high contrast color schema + * + * @param $aFlg True, to use high contrast color + * @param $aBW True, Use only black and white color schema + */ + function UseHighContrastColor($aFlg=true,$aBW=false) { + $this->highcontrast = $aFlg; + $this->highcontrastbw = $aBW; + $this->contour->UseHighContrastColor($this->highcontrast,$this->highcontrastbw); + } + + /** + * Internal method. Stroke the contour plot to the graph + * + * @param $img Image handler + * @param $xscale Instance of the xscale to use + * @param $yscale Instance of the yscale to use + */ + function Stroke($img,$xscale,$yscale) { + + if( count($this->manualIsobarColors) > 0 ) { + $this->contourColor = $this->manualIsobarColors; + if( count($this->manualIsobarColors) != $this->nbrContours ) { + JpGraphError::RaiseL(28002); + } + } + + $img->SetLineWeight($this->line_weight); + + for ($c = 0; $c < $this->nbrContours; $c++) { + + $img->SetColor( $this->contourColor[$c] ); + + $n = count($this->contourCoord[$c]); + $i = 0; + while ( $i < $n ) { + list($x1,$y1) = $this->contourCoord[$c][$i][0]; + $x1t = $xscale->Translate($x1); + $y1t = $yscale->Translate($y1); + + list($x2,$y2) = $this->contourCoord[$c][$i++][1]; + $x2t = $xscale->Translate($x2); + $y2t = $yscale->Translate($y2); + + $img->Line($x1t,$y1t,$x2t,$y2t); + } + + } + } + +} + +// EOF +?> diff --git a/src/classes/jpgraph/jpgraph_date.php b/src/classes/jpgraph/jpgraph_date.php new file mode 100644 index 0000000..db4c441 --- /dev/null +++ b/src/classes/jpgraph/jpgraph_date.php @@ -0,0 +1,499 @@ +type=$aType; + $this->scale=array($aMin,$aMax); + $this->world_size=$aMax-$aMin; + $this->ticks = new LinearTicks(); + $this->intscale=true; + } + + + //------------------------------------------------------------------------------------------ + // Utility Function AdjDate() + // Description: Will round a given time stamp to an even year, month or day + // argument. + //------------------------------------------------------------------------------------------ + + function AdjDate($aTime,$aRound=0,$aYearType=false,$aMonthType=false,$aDayType=false) { + $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); + $h=0;$i=0;$s=0; + if( $aYearType !== false ) { + $yearAdj = array(0=>1, 1=>2, 2=>5); + if( $aRound == 0 ) { + $y = floor($y/$yearAdj[$aYearType])*$yearAdj[$aYearType]; + } + else { + ++$y; + $y = ceil($y/$yearAdj[$aYearType])*$yearAdj[$aYearType]; + } + $m=1;$d=1; + } + elseif( $aMonthType !== false ) { + $monthAdj = array(0=>1, 1=>6); + if( $aRound == 0 ) { + $m = floor($m/$monthAdj[$aMonthType])*$monthAdj[$aMonthType]; + $d=1; + } + else { + ++$m; + $m = ceil($m/$monthAdj[$aMonthType])*$monthAdj[$aMonthType]; + $d=1; + } + } + elseif( $aDayType !== false ) { + if( $aDayType == 0 ) { + if( $aRound == 1 ) { + //++$d; + $h=23;$i=59;$s=59; + } + } + else { + // Adjust to an even week boundary. + $w = (int)date('w',$aTime); // Day of week 0=Sun, 6=Sat + if( true ) { // Adjust to start on Mon + if( $w==0 ) $w=6; + else --$w; + } + if( $aRound == 0 ) { + $d -= $w; + } + else { + $d += (7-$w); + $h=23;$i=59;$s=59; + } + } + } + return mktime($h,$i,$s,$m,$d,$y); + + } + + //------------------------------------------------------------------------------------------ + // Wrapper for AdjDate that will round a timestamp to an even date rounding + // it downwards. + //------------------------------------------------------------------------------------------ + function AdjStartDate($aTime,$aYearType=false,$aMonthType=false,$aDayType=false) { + return $this->AdjDate($aTime,0,$aYearType,$aMonthType,$aDayType); + } + + //------------------------------------------------------------------------------------------ + // Wrapper for AdjDate that will round a timestamp to an even date rounding + // it upwards + //------------------------------------------------------------------------------------------ + function AdjEndDate($aTime,$aYearType=false,$aMonthType=false,$aDayType=false) { + return $this->AdjDate($aTime,1,$aYearType,$aMonthType,$aDayType); + } + + //------------------------------------------------------------------------------------------ + // Utility Function AdjTime() + // Description: Will round a given time stamp to an even time according to + // argument. + //------------------------------------------------------------------------------------------ + + function AdjTime($aTime,$aRound=0,$aHourType=false,$aMinType=false,$aSecType=false) { + $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); + $h = (int)date('H',$aTime); $i = (int)date('i',$aTime); $s = (int)date('s',$aTime); + if( $aHourType !== false ) { + $aHourType %= 6; + $hourAdj = array(0=>1, 1=>2, 2=>3, 3=>4, 4=>6, 5=>12); + if( $aRound == 0 ) + $h = floor($h/$hourAdj[$aHourType])*$hourAdj[$aHourType]; + else { + if( ($h % $hourAdj[$aHourType]==0) && ($i > 0 || $s > 0) ) { + $h++; + } + $h = ceil($h/$hourAdj[$aHourType])*$hourAdj[$aHourType]; + if( $h >= 24 ) { + $aTime += 86400; + $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); + $h -= 24; + } + } + $i=0;$s=0; + } + elseif( $aMinType !== false ) { + $aMinType %= 5; + $minAdj = array(0=>1, 1=>5, 2=>10, 3=>15, 4=>30); + if( $aRound == 0 ) { + $i = floor($i/$minAdj[$aMinType])*$minAdj[$aMinType]; + } + else { + if( ($i % $minAdj[$aMinType]==0) && $s > 0 ) { + $i++; + } + $i = ceil($i/$minAdj[$aMinType])*$minAdj[$aMinType]; + if( $i >= 60) { + $aTime += 3600; + $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); + $h = (int)date('H',$aTime); $i = 0; + } + } + $s=0; + } + elseif( $aSecType !== false ) { + $aSecType %= 5; + $secAdj = array(0=>1, 1=>5, 2=>10, 3=>15, 4=>30); + if( $aRound == 0 ) { + $s = floor($s/$secAdj[$aSecType])*$secAdj[$aSecType]; + } + else { + $s = ceil($s/$secAdj[$aSecType]*1.0)*$secAdj[$aSecType]; + if( $s >= 60) { + $s=0; + $aTime += 60; + $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); + $h = (int)date('H',$aTime); $i = (int)date('i',$aTime); + } + } + } + return mktime($h,$i,$s,$m,$d,$y); + } + + //------------------------------------------------------------------------------------------ + // Wrapper for AdjTime that will round a timestamp to an even time rounding + // it downwards. + // Example: AdjStartTime(mktime(18,27,13,2,22,2005),false,2) => 18:20 + //------------------------------------------------------------------------------------------ + function AdjStartTime($aTime,$aHourType=false,$aMinType=false,$aSecType=false) { + return $this->AdjTime($aTime,0,$aHourType,$aMinType,$aSecType); + } + + //------------------------------------------------------------------------------------------ + // Wrapper for AdjTime that will round a timestamp to an even time rounding + // it upwards + // Example: AdjEndTime(mktime(18,27,13,2,22,2005),false,2) => 18:30 + //------------------------------------------------------------------------------------------ + function AdjEndTime($aTime,$aHourType=false,$aMinType=false,$aSecType=false) { + return $this->AdjTime($aTime,1,$aHourType,$aMinType,$aSecType); + } + + //------------------------------------------------------------------------------------------ + // DateAutoScale + // Autoscale a date axis given start and end time + // Returns an array ($start,$end,$major,$minor,$format) + //------------------------------------------------------------------------------------------ + function DoDateAutoScale($aStartTime,$aEndTime,$aDensity=0,$aAdjust=true) { + // Format of array + // array ( Decision point, array( array( Major-scale-step-array ), + // array( Minor-scale-step-array ), + // array( 0=date-adjust, 1=time-adjust, adjustment-alignment) ) + // + $scalePoints = + array( + /* Intervall larger than 10 years */ + SECPERYEAR*10,array(array(SECPERYEAR*5,SECPERYEAR*2), + array(SECPERYEAR), + array(0,YEARADJ_1, 0,YEARADJ_1) ), + + /* Intervall larger than 2 years */ + SECPERYEAR*2,array(array(SECPERYEAR),array(SECPERYEAR), + array(0,YEARADJ_1) ), + + /* Intervall larger than 90 days (approx 3 month) */ + SECPERDAY*90,array(array(SECPERDAY*30,SECPERDAY*14,SECPERDAY*7,SECPERDAY), + array(SECPERDAY*5,SECPERDAY*7,SECPERDAY,SECPERDAY), + array(0,MONTHADJ_1, 0,DAYADJ_WEEK, 0,DAYADJ_1, 0,DAYADJ_1)), + + /* Intervall larger than 30 days (approx 1 month) */ + SECPERDAY*30,array(array(SECPERDAY*14,SECPERDAY*7,SECPERDAY*2, SECPERDAY), + array(SECPERDAY,SECPERDAY,SECPERDAY,SECPERDAY), + array(0,DAYADJ_WEEK, 0,DAYADJ_1, 0,DAYADJ_1, 0,DAYADJ_1)), + + /* Intervall larger than 7 days */ + SECPERDAY*7,array(array(SECPERDAY,SECPERHOUR*12,SECPERHOUR*6,SECPERHOUR*2), + array(SECPERHOUR*6,SECPERHOUR*3,SECPERHOUR,SECPERHOUR), + array(0,DAYADJ_1, 1,HOURADJ_12, 1,HOURADJ_6, 1,HOURADJ_1)), + + /* Intervall larger than 1 day */ + SECPERDAY,array(array(SECPERDAY,SECPERHOUR*12,SECPERHOUR*6,SECPERHOUR*2,SECPERHOUR), + array(SECPERHOUR*6,SECPERHOUR*2,SECPERHOUR,SECPERHOUR,SECPERHOUR), + array(1,HOURADJ_12, 1,HOURADJ_6, 1,HOURADJ_1, 1,HOURADJ_1)), + + /* Intervall larger than 12 hours */ + SECPERHOUR*12,array(array(SECPERHOUR*2,SECPERHOUR,SECPERMIN*30,900,600), + array(1800,1800,900,300,300), + array(1,HOURADJ_1, 1,MINADJ_30, 1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5) ), + + /* Intervall larger than 2 hours */ + SECPERHOUR*2,array(array(SECPERHOUR,SECPERMIN*30,900,600,300), + array(1800,900,300,120,60), + array(1,HOURADJ_1, 1,MINADJ_30, 1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5) ), + + /* Intervall larger than 1 hours */ + SECPERHOUR,array(array(SECPERMIN*30,900,600,300),array(900,300,120,60), + array(1,MINADJ_30, 1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5) ), + + /* Intervall larger than 30 min */ + SECPERMIN*30,array(array(SECPERMIN*15,SECPERMIN*10,SECPERMIN*5,SECPERMIN), + array(300,300,60,10), + array(1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5, 1,MINADJ_1)), + + /* Intervall larger than 1 min */ + SECPERMIN,array(array(SECPERMIN,15,10,5), + array(15,5,2,1), + array(1,MINADJ_1, 1,SECADJ_15, 1,SECADJ_10, 1,SECADJ_5)), + + /* Intervall larger than 10 sec */ + 10,array(array(5,2), + array(1,1), + array(1,SECADJ_5, 1,SECADJ_1)), + + /* Intervall larger than 1 sec */ + 1,array(array(1), + array(1), + array(1,SECADJ_1)), + ); + + $ns = count($scalePoints); + // Establish major and minor scale units for the date scale + $diff = $aEndTime - $aStartTime; + if( $diff < 1 ) return false; + $done=false; + $i=0; + while( ! $done ) { + if( $diff > $scalePoints[2*$i] ) { + // Get major and minor scale for this intervall + $scaleSteps = $scalePoints[2*$i+1]; + $major = $scaleSteps[0][min($aDensity,count($scaleSteps[0])-1)]; + // Try to find out which minor step looks best + $minor = $scaleSteps[1][min($aDensity,count($scaleSteps[1])-1)]; + if( $aAdjust ) { + // Find out how we should align the start and end timestamps + $idx = 2*min($aDensity,floor(count($scaleSteps[2])/2)-1); + if( $scaleSteps[2][$idx] === 0 ) { + // Use date adjustment + $adj = $scaleSteps[2][$idx+1]; + if( $adj >= 30 ) { + $start = $this->AdjStartDate($aStartTime,$adj-30); + $end = $this->AdjEndDate($aEndTime,$adj-30); + } + elseif( $adj >= 20 ) { + $start = $this->AdjStartDate($aStartTime,false,$adj-20); + $end = $this->AdjEndDate($aEndTime,false,$adj-20); + } + else { + $start = $this->AdjStartDate($aStartTime,false,false,$adj); + $end = $this->AdjEndDate($aEndTime,false,false,$adj); + // We add 1 second for date adjustment to make sure we end on 00:00 the following day + // This makes the final major tick be srawn when we step day-by-day instead of ending + // on xx:59:59 which would not draw the final major tick + $end++; + } + } + else { + // Use time adjustment + $adj = $scaleSteps[2][$idx+1]; + if( $adj >= 30 ) { + $start = $this->AdjStartTime($aStartTime,$adj-30); + $end = $this->AdjEndTime($aEndTime,$adj-30); + } + elseif( $adj >= 20 ) { + $start = $this->AdjStartTime($aStartTime,false,$adj-20); + $end = $this->AdjEndTime($aEndTime,false,$adj-20); + } + else { + $start = $this->AdjStartTime($aStartTime,false,false,$adj); + $end = $this->AdjEndTime($aEndTime,false,false,$adj); + } + } + } + // If the overall date span is larger than 1 day ten we show date + $format = ''; + if( ($end-$start) > SECPERDAY ) { + $format = 'Y-m-d '; + } + // If the major step is less than 1 day we need to whow hours + min + if( $major < SECPERDAY ) { + $format .= 'H:i'; + } + // If the major step is less than 1 min we need to show sec + if( $major < 60 ) { + $format .= ':s'; + } + $done=true; + } + ++$i; + } + return array($start,$end,$major,$minor,$format); + } + + // Overrides the automatic determined date format. Must be a valid date() format string + function SetDateFormat($aFormat) { + $this->date_format = $aFormat; + $this->ticks->SetLabelDateFormat($this->date_format); + } + + function AdjustForDST($aFlg=true) { + $this->ticks->AdjustForDST($aFlg); + } + + + function SetDateAlign($aStartAlign,$aEndAlign=false) { + if( $aEndAlign === false ) { + $aEndAlign=$aStartAlign; + } + $this->iStartAlign = $aStartAlign; + $this->iEndAlign = $aEndAlign; + } + + function SetTimeAlign($aStartAlign,$aEndAlign=false) { + if( $aEndAlign === false ) { + $aEndAlign=$aStartAlign; + } + $this->iStartTimeAlign = $aStartAlign; + $this->iEndTimeAlign = $aEndAlign; + } + + + function AutoScale($img,$aStartTime,$aEndTime,$aNumSteps,$_adummy=false) { + // We need to have one dummy argument to make the signature of AutoScale() + // identical to LinearScale::AutoScale + if( $aStartTime == $aEndTime ) { + // Special case when we only have one data point. + // Create a small artifical intervall to do the autoscaling + $aStartTime -= 10; + $aEndTime += 10; + } + $done=false; + $i=0; + while( ! $done && $i < 5) { + list($adjstart,$adjend,$maj,$min,$format) = $this->DoDateAutoScale($aStartTime,$aEndTime,$i); + $n = floor(($adjend-$adjstart)/$maj); + if( $n * 1.7 > $aNumSteps ) { + $done=true; + } + $i++; + } + + /* + if( 0 ) { // DEBUG + echo " Start =".date("Y-m-d H:i:s",$aStartTime)."
"; + echo " End =".date("Y-m-d H:i:s",$aEndTime)."
"; + echo "Adj Start =".date("Y-m-d H:i:s",$adjstart)."
"; + echo "Adj End =".date("Y-m-d H:i:s",$adjend)."

"; + echo "Major = $maj s, ".floor($maj/60)."min, ".floor($maj/3600)."h, ".floor($maj/86400)."day
"; + echo "Min = $min s, ".floor($min/60)."min, ".floor($min/3600)."h, ".floor($min/86400)."day
"; + echo "Format=$format

"; + } + */ + + if( $this->iStartTimeAlign !== false && $this->iStartAlign !== false ) { + JpGraphError::RaiseL(3001); + //('It is only possible to use either SetDateAlign() or SetTimeAlign() but not both'); + } + + if( $this->iStartTimeAlign !== false ) { + if( $this->iStartTimeAlign >= 30 ) { + $adjstart = $this->AdjStartTime($aStartTime,$this->iStartTimeAlign-30); + } + elseif( $this->iStartTimeAlign >= 20 ) { + $adjstart = $this->AdjStartTime($aStartTime,false,$this->iStartTimeAlign-20); + } + else { + $adjstart = $this->AdjStartTime($aStartTime,false,false,$this->iStartTimeAlign); + } + } + if( $this->iEndTimeAlign !== false ) { + if( $this->iEndTimeAlign >= 30 ) { + $adjend = $this->AdjEndTime($aEndTime,$this->iEndTimeAlign-30); + } + elseif( $this->iEndTimeAlign >= 20 ) { + $adjend = $this->AdjEndTime($aEndTime,false,$this->iEndTimeAlign-20); + } + else { + $adjend = $this->AdjEndTime($aEndTime,false,false,$this->iEndTimeAlign); + } + } + + + + if( $this->iStartAlign !== false ) { + if( $this->iStartAlign >= 30 ) { + $adjstart = $this->AdjStartDate($aStartTime,$this->iStartAlign-30); + } + elseif( $this->iStartAlign >= 20 ) { + $adjstart = $this->AdjStartDate($aStartTime,false,$this->iStartAlign-20); + } + else { + $adjstart = $this->AdjStartDate($aStartTime,false,false,$this->iStartAlign); + } + } + if( $this->iEndAlign !== false ) { + if( $this->iEndAlign >= 30 ) { + $adjend = $this->AdjEndDate($aEndTime,$this->iEndAlign-30); + } + elseif( $this->iEndAlign >= 20 ) { + $adjend = $this->AdjEndDate($aEndTime,false,$this->iEndAlign-20); + } + else { + $adjend = $this->AdjEndDate($aEndTime,false,false,$this->iEndAlign); + } + } + $this->Update($img,$adjstart,$adjend); + if( ! $this->ticks->IsSpecified() ) + $this->ticks->Set($maj,$min); + if( $this->date_format == '' ) + $this->ticks->SetLabelDateFormat($format); + else + $this->ticks->SetLabelDateFormat($this->date_format); + } +} + + +?> diff --git a/src/classes/jpgraph/jpgraph_errhandler.inc.php b/src/classes/jpgraph/jpgraph_errhandler.inc.php index 68b5b5d..c15361e 100644 --- a/src/classes/jpgraph/jpgraph_errhandler.inc.php +++ b/src/classes/jpgraph/jpgraph_errhandler.inc.php @@ -347,6 +347,7 @@ class JpGraphErrObjectImg extends JpGraphErrObject { $img->SetColor("black"); $img->SetFont(FF_FONT1,FS_NORMAL); $txt = new Text($aMsg,52,25); + $txt->SetFont(FF_FONT1); $txt->Align("left","top"); $txt->Stroke($img); if ($this->iDest) { diff --git a/src/classes/jpgraph/jpgraph_error.php b/src/classes/jpgraph/jpgraph_error.php new file mode 100644 index 0000000..3ef3ca5 --- /dev/null +++ b/src/classes/jpgraph/jpgraph_error.php @@ -0,0 +1,157 @@ +numpoints /= 2; + } + //--------------- + // PUBLIC METHODS + + // Gets called before any axis are stroked + function PreStrokeAdjust($graph) { + if( $this->center ) { + $a=0.5; $b=0.5; + ++$this->numpoints; + } else { + $a=0; $b=0; + } + $graph->xaxis->scale->ticks->SetXLabelOffset($a); + $graph->SetTextScaleOff($b); + //$graph->xaxis->scale->ticks->SupressMinorTickMarks(); + } + + // Method description + function Stroke($img,$xscale,$yscale) { + $numpoints=count($this->coords[0])/2; + $img->SetColor($this->color); + $img->SetLineWeight($this->weight); + + if( isset($this->coords[1]) ) { + if( count($this->coords[1])!=$numpoints ) + JpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints); + //("Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])." Number of Y-points:$numpoints"); + else + $exist_x = true; + } + else + $exist_x = false; + + for( $i=0; $i<$numpoints; ++$i) { + if( $exist_x ) + $x=$this->coords[1][$i]; + else + $x=$i; + + if( !is_numeric($x) || + !is_numeric($this->coords[0][$i*2]) || !is_numeric($this->coords[0][$i*2+1]) ) { + continue; + } + + $xt = $xscale->Translate($x); + $yt1 = $yscale->Translate($this->coords[0][$i*2]); + $yt2 = $yscale->Translate($this->coords[0][$i*2+1]); + $img->Line($xt,$yt1,$xt,$yt2); + $img->Line($xt-$this->errwidth,$yt1,$xt+$this->errwidth,$yt1); + $img->Line($xt-$this->errwidth,$yt2,$xt+$this->errwidth,$yt2); + } + return true; + } +} // Class + + +//=================================================== +// CLASS ErrorLinePlot +// Description: Combine a line and error plot +// THIS IS A DEPRECATED PLOT TYPE JUST KEPT FOR +// BACKWARD COMPATIBILITY +//=================================================== +class ErrorLinePlot extends ErrorPlot { + public $line=null; + //--------------- + // CONSTRUCTOR + function __construct($datay,$datax=false) { + parent::__construct($datay,$datax); + // Calculate line coordinates as the average of the error limits + $n = count($datay); + for($i=0; $i < $n; $i+=2 ) { + $ly[]=($datay[$i]+$datay[$i+1])/2; + } + $this->line=new LinePlot($ly,$datax); + } + + //--------------- + // PUBLIC METHODS + function Legend($graph) { + if( $this->legend != "" ) + $graph->legend->Add($this->legend,$this->color); + $this->line->Legend($graph); + } + + function Stroke($img,$xscale,$yscale) { + parent::Stroke($img,$xscale,$yscale); + $this->line->Stroke($img,$xscale,$yscale); + } +} // Class + + +//=================================================== +// CLASS LineErrorPlot +// Description: Combine a line and error plot +//=================================================== +class LineErrorPlot extends ErrorPlot { + public $line=null; + //--------------- + // CONSTRUCTOR + // Data is (val, errdeltamin, errdeltamax) + function __construct($datay,$datax=false) { + $ly=array(); $ey=array(); + $n = count($datay); + if( $n % 3 != 0 ) { + JpGraphError::RaiseL(4002); + //('Error in input data to LineErrorPlot. Number of data points must be a multiple of 3'); + } + for($i=0; $i < $n; $i+=3 ) { + $ly[]=$datay[$i]; + $ey[]=$datay[$i]+$datay[$i+1]; + $ey[]=$datay[$i]+$datay[$i+2]; + } + parent::__construct($ey,$datax); + $this->line=new LinePlot($ly,$datax); + } + + //--------------- + // PUBLIC METHODS + function Legend($graph) { + if( $this->legend != "" ) + $graph->legend->Add($this->legend,$this->color); + $this->line->Legend($graph); + } + + function Stroke($img,$xscale,$yscale) { + parent::Stroke($img,$xscale,$yscale); + $this->line->Stroke($img,$xscale,$yscale); + } +} // Class + + +/* EOF */ +?> diff --git a/src/classes/jpgraph/jpgraph_flags.php b/src/classes/jpgraph/jpgraph_flags.php new file mode 100644 index 0000000..a7e2187 --- /dev/null +++ b/src/classes/jpgraph/jpgraph_flags.php @@ -0,0 +1,376 @@ + 'afgh', + 'Republic of Angola' => 'agla', + 'Republic of Albania' => 'alba', + 'Alderney' => 'alde', + 'Democratic and Popular Republic of Algeria' => 'alge', + 'Territory of American Samoa' => 'amsa', + 'Principality of Andorra' => 'andr', + 'British Overseas Territory of Anguilla' => 'angu', + 'Antarctica' => 'anta', + 'Argentine Republic' => 'arge', + 'League of Arab States' => 'arle', + 'Republic of Armenia' => 'arme', + 'Aruba' => 'arub', + 'Commonwealth of Australia' => 'astl', + 'Republic of Austria' => 'aust', + 'Azerbaijani Republic' => 'azer', + 'Bangladesh' => 'bngl', + 'British Antarctic Territory' => 'bant', + 'Kingdom of Belgium' => 'belg', + 'British Overseas Territory of Bermuda' => 'berm', + 'Commonwealth of the Bahamas' => 'bhms', + 'Kingdom of Bahrain' => 'bhrn', + 'Republic of Belarus' => 'blru', + 'Republic of Bolivia' => 'blva', + 'Belize' => 'blze', + 'Republic of Benin' => 'bnin', + 'Republic of Botswana' => 'bots', + 'Federative Republic of Brazil' => 'braz', + 'Barbados' => 'brbd', + 'British Indian Ocean Territory' => 'brin', + 'Brunei Darussalam' => 'brun', + 'Republic of Burkina' => 'bufa', + 'Republic of Bulgaria' => 'bulg', + 'Republic of Burundi' => 'buru', + 'Overseas Territory of the British Virgin Islands' => 'bvis', + 'Central African Republic' => 'cafr', + 'Kingdom of Cambodia' => 'camb', + 'Republic of Cameroon' => 'came', + 'Dominion of Canada' => 'cana', + 'Caribbean Community' => 'cari', + 'Republic of Cape Verde' => 'cave', + 'Republic of Chad' => 'chad', + 'Republic of Chile' => 'chil', + 'Peoples Republic of China' => 'chin', + 'Territory of Christmas Island' => 'chms', + 'Commonwealth of Independent States' => 'cins', + 'Cook Islands' => 'ckis', + 'Republic of Colombia' => 'clmb', + 'Territory of Cocos Islands' => 'cois', + 'Commonwealth' => 'comn', + 'Union of the Comoros' => 'como', + 'Republic of the Congo' => 'cong', + 'Republic of Costa Rica' => 'corc', + 'Republic of Croatia' => 'croa', + 'Republic of Cuba' => 'cuba', + 'British Overseas Territory of the Cayman Islands' => 'cyis', + 'Republic of Cyprus' => 'cypr', + 'The Czech Republic' => 'czec', + 'Kingdom of Denmark' => 'denm', + 'Republic of Djibouti' => 'djib', + 'Commonwealth of Dominica' => 'domn', + 'Dominican Republic' => 'dore', + 'Republic of Ecuador' => 'ecua', + 'Arab Republic of Egypt' => 'egyp', + 'Republic of El Salvador' => 'elsa', + 'England' => 'engl', + 'Republic of Equatorial Guinea' => 'eqgu', + 'State of Eritrea' => 'erit', + 'Republic of Estonia' => 'estn', + 'Ethiopia' => 'ethp', + 'European Union' => 'euun', + 'British Overseas Territory of the Falkland Islands' => 'fais', + 'International Federation of Vexillological Associations' => 'fiav', + 'Republic of Fiji' => 'fiji', + 'Republic of Finland' => 'finl', + 'Territory of French Polynesia' => 'fpol', + 'French Republic' => 'fran', + 'Overseas Department of French Guiana' => 'frgu', + 'Gabonese Republic' => 'gabn', + 'Republic of the Gambia' => 'gamb', + 'Republic of Georgia' => 'geor', + 'Federal Republic of Germany' => 'germ', + 'Republic of Ghana' => 'ghan', + 'Gibraltar' => 'gibr', + 'Hellenic Republic' => 'grec', + 'State of Grenada' => 'gren', + 'Overseas Department of Guadeloupe' => 'guad', + 'Territory of Guam' => 'guam', + 'Republic of Guatemala' => 'guat', + 'The Bailiwick of Guernsey' => 'guer', + 'Republic of Guinea' => 'guin', + 'Republic of Haiti' => 'hait', + 'Hong Kong Special Administrative Region' => 'hokn', + 'Republic of Honduras' => 'hond', + 'Republic of Hungary' => 'hung', + 'Republic of Iceland' => 'icel', + 'International Committee of the Red Cross' => 'icrc', + 'Republic of India' => 'inda', + 'Republic of Indonesia' => 'indn', + 'Republic of Iraq' => 'iraq', + 'Republic of Ireland' => 'irel', + 'Organization of the Islamic Conference' => 'isco', + 'Isle of Man' => 'isma', + 'State of Israel' => 'isra', + 'Italian Republic' => 'ital', + 'Jamaica' => 'jama', + 'Japan' => 'japa', + 'The Bailiwick of Jersey' => 'jers', + 'Hashemite Kingdom of Jordan' => 'jord', + 'Republic of Kazakhstan' => 'kazk', + 'Republic of Kenya' => 'keny', + 'Republic of Kiribati' => 'kirb', + 'State of Kuwait' => 'kuwa', + 'Kyrgyz Republic' => 'kyrg', + 'Republic of Latvia' => 'latv', + 'Lebanese Republic' => 'leba', + 'Kingdom of Lesotho' => 'lest', + 'Republic of Liberia' => 'libe', + 'Principality of Liechtenstein' => 'liec', + 'Republic of Lithuania' => 'lith', + 'Grand Duchy of Luxembourg' => 'luxe', + 'Macao Special Administrative Region' => 'maca', + 'Republic of Macedonia' => 'mace', + 'Republic of Madagascar' => 'mada', + 'Republic of the Marshall Islands' => 'mais', + 'Republic of Mali' => 'mali', + 'Federation of Malaysia' => 'mals', + 'Republic of Malta' => 'malt', + 'Republic of Malawi' => 'malw', + 'Overseas Department of Martinique' => 'mart', + 'Islamic Republic of Mauritania' => 'maur', + 'Territorial Collectivity of Mayotte' => 'mayt', + 'United Mexican States' => 'mexc', + 'Federated States of Micronesia' => 'micr', + 'Midway Islands' => 'miis', + 'Republic of Moldova' => 'mold', + 'Principality of Monaco' => 'mona', + 'Republic of Mongolia' => 'mong', + 'British Overseas Territory of Montserrat' => 'mont', + 'Kingdom of Morocco' => 'morc', + 'Republic of Mozambique' => 'moza', + 'Republic of Mauritius' => 'mrts', + 'Union of Myanmar' => 'myan', + 'Republic of Namibia' => 'namb', + 'North Atlantic Treaty Organization' => 'nato', + 'Republic of Nauru' => 'naur', + 'Turkish Republic of Northern Cyprus' => 'ncyp', + 'Netherlands Antilles' => 'nean', + 'Kingdom of Nepal' => 'nepa', + 'Kingdom of the Netherlands' => 'neth', + 'Territory of Norfolk Island' => 'nfis', + 'Federal Republic of Nigeria' => 'ngra', + 'Republic of Nicaragua' => 'nica', + 'Republic of Niger' => 'nigr', + 'Niue' => 'niue', + 'Commonwealth of the Northern Mariana Islands' => 'nmar', + 'Province of Northern Ireland' => 'noir', + 'Nordic Council' => 'nord', + 'Kingdom of Norway' => 'norw', + 'Territory of New Caledonia and Dependencies' => 'nwca', + 'New Zealand' => 'nwze', + 'Organization of American States' => 'oast', + 'Organization of African Unity' => 'oaun', + 'International Olympic Committee' => 'olym', + 'Sultanate of Oman' => 'oman', + 'Islamic Republic of Pakistan' => 'paks', + 'Republic of Palau' => 'pala', + 'Independent State of Papua New Guinea' => 'pang', + 'Republic of Paraguay' => 'para', + 'Republic of Peru' => 'peru', + 'Republic of the Philippines' => 'phil', + 'British Overseas Territory of the Pitcairn Islands' => 'piis', + 'Republic of Poland' => 'pola', + 'Republic of Portugal' => 'port', + 'Commonwealth of Puerto Rico' => 'purc', + 'State of Qatar' => 'qata', + 'Russian Federation' => 'russ', + 'Romania' => 'rmna', + 'Republic of Rwanda' => 'rwan', + 'Kingdom of Saudi Arabia' => 'saar', + 'Republic of San Marino' => 'sama', + 'Nordic Sami Conference' => 'sami', + 'Sark' => 'sark', + 'Scotland' => 'scot', + 'Principality of Seborga' => 'sebo', + 'Republic of Serbia' => 'serb', + 'Republic of Sierra Leone' => 'sile', + 'Republic of Singapore' => 'sing', + 'Republic of Korea' => 'skor', + 'Republic of Slovenia' => 'slva', + 'Somali Republic' => 'smla', + 'Republic of Somaliland' => 'smld', + 'Republic of South Africa' => 'soaf', + 'Solomon Islands' => 'sois', + 'Kingdom of Spain' => 'span', + 'Secretariat of the Pacific Community' => 'spco', + 'Democratic Socialist Republic of Sri Lanka' => 'srla', + 'Saint Lucia' => 'stlu', + 'Republic of the Sudan' => 'suda', + 'Republic of Suriname' => 'surn', + 'Slovak Republic' => 'svka', + 'Kingdom of Sweden' => 'swdn', + 'Swiss Confederation' => 'swit', + 'Syrian Arab Republic' => 'syra', + 'Kingdom of Swaziland' => 'szld', + 'Republic of China' => 'taiw', + 'Taiwan' => 'taiw', + 'Republic of Tajikistan' => 'tajk', + 'United Republic of Tanzania' => 'tanz', + 'Kingdom of Thailand' => 'thal', + 'Autonomous Region of Tibet' => 'tibe', + 'Turkmenistan' => 'tkst', + 'Togolese Republic' => 'togo', + 'Tokelau' => 'toke', + 'Kingdom of Tonga' => 'tong', + 'Tristan da Cunha' => 'trdc', + 'Tromelin' => 'tris', + 'Republic of Tunisia' => 'tuns', + 'Republic of Turkey' => 'turk', + 'Tuvalu' => 'tuva', + 'United Arab Emirates' => 'uaem', + 'Republic of Uganda' => 'ugan', + 'Ukraine' => 'ukrn', + 'United Kingdom of Great Britain' => 'unkg', + 'United Nations' => 'unna', + 'United States of America' => 'unst', + 'Oriental Republic of Uruguay' => 'urgy', + 'Virgin Islands of the United States' => 'usvs', + 'Republic of Uzbekistan' => 'uzbk', + 'State of the Vatican City' => 'vacy', + 'Republic of Vanuatu' => 'vant', + 'Bolivarian Republic of Venezuela' => 'venz', + 'Republic of Yemen' => 'yemn', + 'Democratic Republic of Congo' => 'zare', + 'Republic of Zimbabwe' => 'zbwe' ) ; + + + private $iFlagCount = -1; + private $iFlagSetMap = array( + FLAGSIZE1 => 'flags_thumb35x35', + FLAGSIZE2 => 'flags_thumb60x60', + FLAGSIZE3 => 'flags_thumb100x100', + FLAGSIZE4 => 'flags' + ); + + private $iFlagData ; + private $iOrdIdx=array(); + + function FlagImages($aSize=FLAGSIZE1) { + switch($aSize) { + case FLAGSIZE1 : + case FLAGSIZE2 : + case FLAGSIZE3 : + case FLAGSIZE4 : + $file = dirname(__FILE__).'/'.$this->iFlagSetMap[$aSize].'.dat'; + $fp = fopen($file,'rb'); + $rawdata = fread($fp,filesize($file)); + $this->iFlagData = unserialize($rawdata); + break; + default: + JpGraphError::RaiseL(5001,$aSize); + //('Unknown flag size. ('.$aSize.')'); + } + $this->iFlagCount = count($this->iCountryNameMap); + } + + function GetNum() { + return $this->iFlagCount; + } + + function GetImgByName($aName,&$outFullName) { + $idx = $this->GetIdxByName($aName,$outFullName); + return $this->GetImgByIdx($idx); + } + + function GetImgByIdx($aIdx) { + if( array_key_exists($aIdx,$this->iFlagData) ) { + $d = $this->iFlagData[$aIdx][1]; + return Image::CreateFromString($d); + } + else { + JpGraphError::RaiseL(5002,$aIdx); + //("Flag index \"�$aIdx\" does not exist."); + } + } + + function GetIdxByOrdinal($aOrd,&$outFullName) { + $aOrd--; + $n = count($this->iOrdIdx); + if( $n == 0 ) { + reset($this->iCountryNameMap); + $this->iOrdIdx=array(); + $i=0; + while( list($key,$val) = each($this->iCountryNameMap) ) { + $this->iOrdIdx[$i++] = array($val,$key); + } + $tmp=$this->iOrdIdx[$aOrd]; + $outFullName = $tmp[1]; + return $tmp[0]; + + } + elseif( $aOrd >= 0 && $aOrd < $n ) { + $tmp=$this->iOrdIdx[$aOrd]; + $outFullName = $tmp[1]; + return $tmp[0]; + } + else { + JpGraphError::RaiseL(5003,$aOrd); + //('Invalid ordinal number specified for flag index.'); + } + } + + function GetIdxByName($aName,&$outFullName) { + + if( is_integer($aName) ) { + $idx = $this->GetIdxByOrdinal($aName,$outFullName); + return $idx; + } + + $found=false; + $aName = strtolower($aName); + $nlen = strlen($aName); + reset($this->iCountryNameMap); + // Start by trying to match exact index name + while( list($key,$val) = each($this->iCountryNameMap) ) { + if( $nlen == strlen($val) && $val == $aName ) { + $found=true; + break; + } + } + if( !$found ) { + reset($this->iCountryNameMap); + // If the exact index doesn't work try a (partial) full name + while( list($key,$val) = each($this->iCountryNameMap) ) { + if( strpos(strtolower($key), $aName) !== false ) { + $found=true; + break; + } + } + } + if( $found ) { + $outFullName = $key; + return $val; + } + else { + JpGraphError::RaiseL(5004,$aName); + //("The (partial) country name \"$aName\" does not have a cooresponding flag image. The flag may still exist but under another name, e.g. insted of \"usa\" try \"united states\"."); + } + } +} + + + + +?> diff --git a/src/classes/jpgraph/jpgraph_gantt.php b/src/classes/jpgraph/jpgraph_gantt.php new file mode 100644 index 0000000..d5afa65 --- /dev/null +++ b/src/classes/jpgraph/jpgraph_gantt.php @@ -0,0 +1,3955 @@ +vgrid = new LineProperty(); + } + + function Hide($aF=true) { + $this->iShow=!$aF; + } + + function Show($aF=true) { + $this->iShow=$aF; + } + + // Specify font + function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) { + $this->iFFamily = $aFFamily; + $this->iFStyle = $aFStyle; + $this->iFSize = $aFSize; + } + + function SetStyle($aStyle) { + $this->iStyle = $aStyle; + } + + function SetColumnMargin($aLeft,$aRight) { + $this->iLeftColMargin = $aLeft; + $this->iRightColMargin = $aRight; + } + + function SetFontColor($aFontColor) { + $this->iFontColor = $aFontColor; + } + + function SetColor($aColor) { + $this->iColor = $aColor; + } + + function SetBackgroundColor($aColor) { + $this->iBackgroundColor = $aColor; + } + + function SetColTitles($aTitles,$aWidth=null) { + $this->iTitles = $aTitles; + $this->iWidth = $aWidth; + } + + function SetMinColWidth($aWidths) { + $n = min(count($this->iTitles),count($aWidths)); + for($i=0; $i < $n; ++$i ) { + if( !empty($aWidths[$i]) ) { + if( empty($this->iWidth[$i]) ) { + $this->iWidth[$i] = $aWidths[$i]; + } + else { + $this->iWidth[$i] = max($this->iWidth[$i],$aWidths[$i]); + } + } + } + } + + function GetWidth($aImg) { + $txt = new TextProperty(); + $txt->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + $n = count($this->iTitles) ; + $rm=$this->iRightColMargin; + $w = 0; + for($h=0, $i=0; $i < $n; ++$i ) { + $w += $this->iLeftColMargin; + $txt->Set($this->iTitles[$i]); + if( !empty($this->iWidth[$i]) ) { + $w1 = max($txt->GetWidth($aImg)+$rm,$this->iWidth[$i]); + } + else { + $w1 = $txt->GetWidth($aImg)+$rm; + } + $this->iWidth[$i] = $w1; + $w += $w1; + $h = max($h,$txt->GetHeight($aImg)); + } + $this->iHeight = $h+$this->iTopHeaderMargin; + $txt=''; + return $w; + } + + function GetColStart($aImg,&$aStart,$aAddLeftMargin=false) { + $n = count($this->iTitles) ; + $adj = $aAddLeftMargin ? $this->iLeftColMargin : 0; + $aStart=array($aImg->left_margin+$adj); + for( $i=1; $i < $n; ++$i ) { + $aStart[$i] = $aStart[$i-1]+$this->iLeftColMargin+$this->iWidth[$i-1]; + } + } + + // Adjust headers left, right or centered + function SetHeaderAlign($aAlign) { + $this->iHeaderAlign=$aAlign; + } + + function Stroke($aImg,$aXLeft,$aYTop,$aXRight,$aYBottom,$aUseTextHeight=false) { + + if( !$this->iShow ) return; + + $txt = new TextProperty(); + $txt->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + $txt->SetColor($this->iFontColor); + $txt->SetAlign($this->iHeaderAlign,'top'); + $n=count($this->iTitles); + + if( $n == 0 ) + return; + + $x = $aXLeft; + $h = $this->iHeight; + $yTop = $aUseTextHeight ? $aYBottom-$h-$this->iTopColMargin-$this->iBottomColMargin : $aYTop ; + + if( $h < 0 ) { + JpGraphError::RaiseL(6001); + //('Internal error. Height for ActivityTitles is < 0'); + } + + $aImg->SetLineWeight(1); + // Set background color + $aImg->SetColor($this->iBackgroundColor); + $aImg->FilledRectangle($aXLeft,$yTop,$aXRight,$aYBottom-1); + + if( $this->iStyle == 1 ) { + // Make a 3D effect + $aImg->SetColor('white'); + $aImg->Line($aXLeft,$yTop+1,$aXRight,$yTop+1); + } + + for($i=0; $i < $n; ++$i ) { + if( $this->iStyle == 1 ) { + // Make a 3D effect + $aImg->SetColor('white'); + $aImg->Line($x+1,$yTop,$x+1,$aYBottom); + } + $x += $this->iLeftColMargin; + $txt->Set($this->iTitles[$i]); + + // Adjust the text anchor position according to the choosen alignment + $xp = $x; + if( $this->iHeaderAlign == 'center' ) { + $xp = (($x-$this->iLeftColMargin)+($x+$this->iWidth[$i]))/2; + } + elseif( $this->iHeaderAlign == 'right' ) { + $xp = $x +$this->iWidth[$i]-$this->iRightColMargin; + } + + $txt->Stroke($aImg,$xp,$yTop+$this->iTopHeaderMargin); + $x += $this->iWidth[$i]; + if( $i < $n-1 ) { + $aImg->SetColor($this->iColor); + $aImg->Line($x,$yTop,$x,$aYBottom); + } + } + + $aImg->SetColor($this->iColor); + $aImg->Line($aXLeft,$yTop, $aXRight,$yTop); + + // Stroke vertical column dividers + $cols=array(); + $this->GetColStart($aImg,$cols); + $n=count($cols); + for( $i=1; $i < $n; ++$i ) { + $this->vgrid->Stroke($aImg,$cols[$i],$aYBottom,$cols[$i], + $aImg->height - $aImg->bottom_margin); + } + } +} + + +//=================================================== +// CLASS GanttGraph +// Description: Main class to handle gantt graphs +//=================================================== +class GanttGraph extends Graph { + public $scale; // Public accessible + public $hgrid=null; + private $iObj=array(); // Gantt objects + private $iLabelHMarginFactor=0.2; // 10% margin on each side of the labels + private $iLabelVMarginFactor=0.4; // 40% margin on top and bottom of label + private $iLayout=GANTT_FROMTOP; // Could also be GANTT_EVEN + private $iSimpleFont = FF_FONT1,$iSimpleFontSize=11; + private $iSimpleStyle=GANTT_RDIAG,$iSimpleColor='yellow',$iSimpleBkgColor='red'; + private $iSimpleProgressBkgColor='gray',$iSimpleProgressColor='darkgreen'; + private $iSimpleProgressStyle=GANTT_SOLID; + private $iZoomFactor = 1.0; + //--------------- + // CONSTRUCTOR + // Create a new gantt graph + function __construct($aWidth=0,$aHeight=0,$aCachedName="",$aTimeOut=0,$aInline=true) { + + // Backward compatibility + if( $aWidth == -1 ) $aWidth=0; + if( $aHeight == -1 ) $aHeight=0; + + if( $aWidth< 0 || $aHeight < 0 ) { + JpgraphError::RaiseL(6002); + //("You can't specify negative sizes for Gantt graph dimensions. Use 0 to indicate that you want the library to automatically determine a dimension."); + } + parent::__construct($aWidth,$aHeight,$aCachedName,$aTimeOut,$aInline); + $this->scale = new GanttScale($this->img); + + // Default margins + $this->img->SetMargin(15,17,25,15); + + $this->hgrid = new HorizontalGridLine(); + + $this->scale->ShowHeaders(GANTT_HWEEK|GANTT_HDAY); + $this->SetBox(); + } + + //--------------- + // PUBLIC METHODS + + // + + function SetSimpleFont($aFont,$aSize) { + $this->iSimpleFont = $aFont; + $this->iSimpleFontSize = $aSize; + } + + function SetSimpleStyle($aBand,$aColor,$aBkgColor) { + $this->iSimpleStyle = $aBand; + $this->iSimpleColor = $aColor; + $this->iSimpleBkgColor = $aBkgColor; + } + + // A utility function to help create basic Gantt charts + function CreateSimple($data,$constrains=array(),$progress=array()) { + $num = count($data); + for( $i=0; $i < $num; ++$i) { + switch( $data[$i][1] ) { + case ACTYPE_GROUP: + // Create a slightly smaller height bar since the + // "wings" at the end will make it look taller + $a = new GanttBar($data[$i][0],$data[$i][2],$data[$i][3],$data[$i][4],'',8); + $a->title->SetFont($this->iSimpleFont,FS_BOLD,$this->iSimpleFontSize); + $a->rightMark->Show(); + $a->rightMark->SetType(MARK_RIGHTTRIANGLE); + $a->rightMark->SetWidth(8); + $a->rightMark->SetColor('black'); + $a->rightMark->SetFillColor('black'); + + $a->leftMark->Show(); + $a->leftMark->SetType(MARK_LEFTTRIANGLE); + $a->leftMark->SetWidth(8); + $a->leftMark->SetColor('black'); + $a->leftMark->SetFillColor('black'); + + $a->SetPattern(BAND_SOLID,'black'); + $csimpos = 6; + break; + + case ACTYPE_NORMAL: + $a = new GanttBar($data[$i][0],$data[$i][2],$data[$i][3],$data[$i][4],'',10); + $a->title->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize); + $a->SetPattern($this->iSimpleStyle,$this->iSimpleColor); + $a->SetFillColor($this->iSimpleBkgColor); + // Check if this activity should have a constrain line + $n = count($constrains); + for( $j=0; $j < $n; ++$j ) { + if( empty($constrains[$j]) || (count($constrains[$j]) != 3) ) { + JpGraphError::RaiseL(6003,$j); + //("Invalid format for Constrain parameter at index=$j in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Constrain-To,Constrain-Type)"); + } + if( $constrains[$j][0]==$data[$i][0] ) { + $a->SetConstrain($constrains[$j][1],$constrains[$j][2],'black',ARROW_S2,ARROWT_SOLID); + } + } + + // Check if this activity have a progress bar + $n = count($progress); + for( $j=0; $j < $n; ++$j ) { + + if( empty($progress[$j]) || (count($progress[$j]) != 2) ) { + JpGraphError::RaiseL(6004,$j); + //("Invalid format for Progress parameter at index=$j in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Progress)"); + } + if( $progress[$j][0]==$data[$i][0] ) { + $a->progress->Set($progress[$j][1]); + $a->progress->SetPattern($this->iSimpleProgressStyle, + $this->iSimpleProgressColor); + $a->progress->SetFillColor($this->iSimpleProgressBkgColor); + //$a->progress->SetPattern($progress[$j][2],$progress[$j][3]); + break; + } + } + $csimpos = 6; + break; + + case ACTYPE_MILESTONE: + $a = new MileStone($data[$i][0],$data[$i][2],$data[$i][3]); + $a->title->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize); + $a->caption->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize); + $csimpos = 5; + break; + default: + die('Unknown activity type'); + break; + } + + // Setup caption + $a->caption->Set($data[$i][$csimpos-1]); + + // Check if this activity should have a CSIM target�? + if( !empty($data[$i][$csimpos]) ) { + $a->SetCSIMTarget($data[$i][$csimpos]); + $a->SetCSIMAlt($data[$i][$csimpos+1]); + } + if( !empty($data[$i][$csimpos+2]) ) { + $a->title->SetCSIMTarget($data[$i][$csimpos+2]); + $a->title->SetCSIMAlt($data[$i][$csimpos+3]); + } + + $this->Add($a); + } + } + + // Set user specified scale zoom factor when auto sizing is used + function SetZoomFactor($aZoom) { + $this->iZoomFactor = $aZoom; + } + + + // Set what headers should be shown + function ShowHeaders($aFlg) { + $this->scale->ShowHeaders($aFlg); + } + + // Specify the fraction of the font height that should be added + // as vertical margin + function SetLabelVMarginFactor($aVal) { + $this->iLabelVMarginFactor = $aVal; + } + + // Synonym to the method above + function SetVMarginFactor($aVal) { + $this->iLabelVMarginFactor = $aVal; + } + + + // Add a new Gantt object + function Add($aObject) { + if( is_array($aObject) && count($aObject) > 0 ) { + $cl = $aObject[0]; + if( class_exists('IconPlot',false) && ($cl instanceof IconPlot) ) { + $this->AddIcon($aObject); + } + elseif( class_exists('Text',false) && ($cl instanceof Text) ) { + $this->AddText($aObject); + } + else { + $n = count($aObject); + for($i=0; $i < $n; ++$i) + $this->iObj[] = $aObject[$i]; + } + } + else { + if( class_exists('IconPlot',false) && ($aObject instanceof IconPlot) ) { + $this->AddIcon($aObject); + } + elseif( class_exists('Text',false) && ($aObject instanceof Text) ) { + $this->AddText($aObject); + } + else { + $this->iObj[] = $aObject; + } + } + } + + function StrokeTexts() { + // Stroke any user added text objects + if( $this->texts != null ) { + $n = count($this->texts); + for($i=0; $i < $n; ++$i) { + if( $this->texts[$i]->iScalePosX !== null && $this->texts[$i]->iScalePosY !== null ) { + $x = $this->scale->TranslateDate($this->texts[$i]->iScalePosX); + $y = $this->scale->TranslateVertPos($this->texts[$i]->iScalePosY); + $y -= $this->scale->GetVertSpacing()/2; + } + else { + $x = $y = null; + } + $this->texts[$i]->Stroke($this->img,$x,$y); + } + } + } + + // Override inherit method from Graph and give a warning message + function SetScale($aAxisType,$aYMin=1,$aYMax=1,$aXMin=1,$aXMax=1) { + JpGraphError::RaiseL(6005); + //("SetScale() is not meaningfull with Gantt charts."); + } + + // Specify the date range for Gantt graphs (if this is not set it will be + // automtically determined from the input data) + function SetDateRange($aStart,$aEnd) { + // Adjust the start and end so that the indicate the + // begining and end of respective start and end days + if( strpos($aStart,':') === false ) + $aStart = date('Y-m-d 00:00',strtotime($aStart)); + if( strpos($aEnd,':') === false ) + $aEnd = date('Y-m-d 23:59',strtotime($aEnd)); + $this->scale->SetRange($aStart,$aEnd); + } + + // Get the maximum width of the activity titles columns for the bars + // The name is lightly misleading since we from now on can have + // multiple columns in the label section. When this was first written + // it only supported a single label, hence the name. + function GetMaxLabelWidth() { + $m=10; + if( $this->iObj != null ) { + $marg = $this->scale->actinfo->iLeftColMargin+$this->scale->actinfo->iRightColMargin; + $n = count($this->iObj); + for($i=0; $i < $n; ++$i) { + if( !empty($this->iObj[$i]->title) ) { + if( $this->iObj[$i]->title->HasTabs() ) { + list($tot,$w) = $this->iObj[$i]->title->GetWidth($this->img,true); + $m=max($m,$tot); + } + else + $m=max($m,$this->iObj[$i]->title->GetWidth($this->img)); + } + } + } + return $m; + } + + // Get the maximum height of the titles for the bars + function GetMaxLabelHeight() { + $m=10; + if( $this->iObj != null ) { + $n = count($this->iObj); + // We can not include the title of GnttVLine since that title is stroked at the bottom + // of the Gantt bar and not in the activity title columns + for($i=0; $i < $n; ++$i) { + if( !empty($this->iObj[$i]->title) && !($this->iObj[$i] instanceof GanttVLine) ) { + $m=max($m,$this->iObj[$i]->title->GetHeight($this->img)); + } + } + } + return $m; + } + + function GetMaxBarAbsHeight() { + $m=0; + if( $this->iObj != null ) { + $m = $this->iObj[0]->GetAbsHeight($this->img); + $n = count($this->iObj); + for($i=1; $i < $n; ++$i) { + $m=max($m,$this->iObj[$i]->GetAbsHeight($this->img)); + } + } + return $m; + } + + // Get the maximum used line number (vertical position) for bars + function GetBarMaxLineNumber() { + $m=1; + if( $this->iObj != null ) { + $m = $this->iObj[0]->GetLineNbr(); + $n = count($this->iObj); + for($i=1; $i < $n; ++$i) { + $m=max($m,$this->iObj[$i]->GetLineNbr()); + } + } + return $m; + } + + // Get the minumum and maximum used dates for all bars + function GetBarMinMax() { + $start = 0 ; + $n = count($this->iObj); + while( $start < $n && $this->iObj[$start]->GetMaxDate() === false ) + ++$start; + if( $start >= $n ) { + JpgraphError::RaiseL(6006); + //('Cannot autoscale Gantt chart. No dated activities exist. [GetBarMinMax() start >= n]'); + } + + $max=$this->scale->NormalizeDate($this->iObj[$start]->GetMaxDate()); + $min=$this->scale->NormalizeDate($this->iObj[$start]->GetMinDate()); + + for($i=$start+1; $i < $n; ++$i) { + $rmax = $this->scale->NormalizeDate($this->iObj[$i]->GetMaxDate()); + if( $rmax != false ) + $max=Max($max,$rmax); + $rmin = $this->scale->NormalizeDate($this->iObj[$i]->GetMinDate()); + if( $rmin != false ) + $min=Min($min,$rmin); + } + $minDate = date("Y-m-d",$min); + $min = strtotime($minDate); + $maxDate = date("Y-m-d 23:59",$max); + $max = strtotime($maxDate); + return array($min,$max); + } + + // Create a new auto sized canvas if the user hasn't specified a size + // The size is determined by what scale the user has choosen and hence + // the minimum width needed to display the headers. Some margins are + // also added to make it better looking. + function AutoSize() { + + if( $this->img->img == null ) { + // The predefined left, right, top, bottom margins. + // Note that the top margin might incease depending on + // the title. + $hadj = $vadj = 0; + if( $this->doshadow ) { + $hadj = $this->shadow_width; + $vadj = $this->shadow_width+5; + } + + $lm = $this->img->left_margin; + $rm = $this->img->right_margin +$hadj; + $rm += 2 ; + $tm = $this->img->top_margin; + $bm = $this->img->bottom_margin + $vadj; + $bm += 2; + + // If there are any added GanttVLine we must make sure that the + // bottom margin is wide enough to hold a title. + $n = count($this->iObj); + for($i=0; $i < $n; ++$i) { + if( $this->iObj[$i] instanceof GanttVLine ) { + $bm = max($bm,$this->iObj[$i]->title->GetHeight($this->img)+10); + } + } + + // First find out the height + $n=$this->GetBarMaxLineNumber()+1; + $m=max($this->GetMaxLabelHeight(),$this->GetMaxBarAbsHeight()); + $height=$n*((1+$this->iLabelVMarginFactor)*$m); + + // Add the height of the scale titles + $h=$this->scale->GetHeaderHeight(); + $height += $h; + + // Calculate the top margin needed for title and subtitle + if( $this->title->t != "" ) { + $tm += $this->title->GetFontHeight($this->img); + } + if( $this->subtitle->t != "" ) { + $tm += $this->subtitle->GetFontHeight($this->img); + } + + // ...and then take the bottom and top plot margins into account + $height += $tm + $bm + $this->scale->iTopPlotMargin + $this->scale->iBottomPlotMargin; + // Now find the minimum width for the chart required + + // If day scale or smaller is shown then we use the day font width + // as the base size unit. + // If only weeks or above is displayed we use a modified unit to + // get a smaller image. + if( $this->scale->IsDisplayHour() || $this->scale->IsDisplayMinute() ) { + // Add 2 pixel margin on each side + $fw=$this->scale->day->GetFontWidth($this->img)+4; + } + elseif( $this->scale->IsDisplayWeek() ) { + $fw = 8; + } + elseif( $this->scale->IsDisplayMonth() ) { + $fw = 4; + } + else { + $fw = 2; + } + + $nd=$this->scale->GetNumberOfDays(); + + if( $this->scale->IsDisplayDay() ) { + // If the days are displayed we also need to figure out + // how much space each day's title will require. + switch( $this->scale->day->iStyle ) { + case DAYSTYLE_LONG : + $txt = "Monday"; + break; + case DAYSTYLE_LONGDAYDATE1 : + $txt = "Monday 23 Jun"; + break; + case DAYSTYLE_LONGDAYDATE2 : + $txt = "Monday 23 Jun 2003"; + break; + case DAYSTYLE_SHORT : + $txt = "Mon"; + break; + case DAYSTYLE_SHORTDAYDATE1 : + $txt = "Mon 23/6"; + break; + case DAYSTYLE_SHORTDAYDATE2 : + $txt = "Mon 23 Jun"; + break; + case DAYSTYLE_SHORTDAYDATE3 : + $txt = "Mon 23"; + break; + case DAYSTYLE_SHORTDATE1 : + $txt = "23/6"; + break; + case DAYSTYLE_SHORTDATE2 : + $txt = "23 Jun"; + break; + case DAYSTYLE_SHORTDATE3 : + $txt = "Mon 23"; + break; + case DAYSTYLE_SHORTDATE4 : + $txt = "88"; + break; + case DAYSTYLE_CUSTOM : + $txt = date($this->scale->day->iLabelFormStr,strtotime('2003-12-20 18:00')); + break; + case DAYSTYLE_ONELETTER : + default: + $txt = "M"; + break; + } + $fw = $this->scale->day->GetStrWidth($this->img,$txt)+6; + } + + // If we have hours enabled we must make sure that each day has enough + // space to fit the number of hours to be displayed. + if( $this->scale->IsDisplayHour() ) { + // Depending on what format the user has choose we need different amount + // of space. We therefore create a typical string for the choosen format + // and determine the length of that string. + switch( $this->scale->hour->iStyle ) { + case HOURSTYLE_HMAMPM: + $txt = '12:00pm'; + break; + case HOURSTYLE_H24: + // 13 + $txt = '24'; + break; + case HOURSTYLE_HAMPM: + $txt = '12pm'; + break; + case HOURSTYLE_CUSTOM: + $txt = date($this->scale->hour->iLabelFormStr,strtotime('2003-12-20 18:00')); + break; + case HOURSTYLE_HM24: + default: + $txt = '24:00'; + break; + } + + $hfw = $this->scale->hour->GetStrWidth($this->img,$txt)+6; + $mw = $hfw; + if( $this->scale->IsDisplayMinute() ) { + // Depending on what format the user has choose we need different amount + // of space. We therefore create a typical string for the choosen format + // and determine the length of that string. + switch( $this->scale->minute->iStyle ) { + case HOURSTYLE_CUSTOM: + $txt2 = date($this->scale->minute->iLabelFormStr,strtotime('2005-05-15 18:55')); + break; + case MINUTESTYLE_MM: + default: + $txt2 = '15'; + break; + } + + $mfw = $this->scale->minute->GetStrWidth($this->img,$txt2)+6; + $n2 = ceil(60 / $this->scale->minute->GetIntervall() ); + $mw = $n2 * $mfw; + } + $hfw = $hfw < $mw ? $mw : $hfw ; + $n = ceil(24*60 / $this->scale->TimeToMinutes($this->scale->hour->GetIntervall()) ); + $hw = $n * $hfw; + $fw = $fw < $hw ? $hw : $fw ; + } + + // We need to repeat this code block here as well. + // THIS iS NOT A MISTAKE ! + // We really need it since we need to adjust for minutes both in the case + // where hour scale is shown and when it is not shown. + + if( $this->scale->IsDisplayMinute() ) { + // Depending on what format the user has choose we need different amount + // of space. We therefore create a typical string for the choosen format + // and determine the length of that string. + switch( $this->scale->minute->iStyle ) { + case HOURSTYLE_CUSTOM: + $txt = date($this->scale->minute->iLabelFormStr,strtotime('2005-05-15 18:55')); + break; + case MINUTESTYLE_MM: + default: + $txt = '15'; + break; + } + + $mfw = $this->scale->minute->GetStrWidth($this->img,$txt)+6; + $n = ceil(60 / $this->scale->TimeToMinutes($this->scale->minute->GetIntervall()) ); + $mw = $n * $mfw; + $fw = $fw < $mw ? $mw : $fw ; + } + + // If we display week we must make sure that 7*$fw is enough + // to fit up to 10 characters of the week font (if the week is enabled) + if( $this->scale->IsDisplayWeek() ) { + // Depending on what format the user has choose we need different amount + // of space + $fsw = strlen($this->scale->week->iLabelFormStr); + if( $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) { + $fsw += 8; + } + elseif( $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ) { + $fsw += 7; + } + else { + $fsw += 4; + } + + $ww = $fsw*$this->scale->week->GetFontWidth($this->img); + if( 7*$fw < $ww ) { + $fw = ceil($ww/7); + } + } + + if( !$this->scale->IsDisplayDay() && !$this->scale->IsDisplayHour() && + !( ($this->scale->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR || + $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR) && $this->scale->IsDisplayWeek() ) ) { + // If we don't display the individual days we can shrink the + // scale a little bit. This is a little bit pragmatic at the + // moment and should be re-written to take into account + // a) What scales exactly are shown and + // b) what format do they use so we know how wide we need to + // make each scale text space at minimum. + $fw /= 2; + if( !$this->scale->IsDisplayWeek() ) { + $fw /= 1.8; + } + } + + $cw = $this->GetMaxActInfoColWidth() ; + $this->scale->actinfo->SetMinColWidth($cw); + if( $this->img->width <= 0 ) { + // Now determine the width for the activity titles column + + // Firdst find out the maximum width of each object column + $titlewidth = max(max($this->GetMaxLabelWidth(), + $this->scale->tableTitle->GetWidth($this->img)), + $this->scale->actinfo->GetWidth($this->img)); + + // Add the width of the vertivcal divider line + $titlewidth += $this->scale->divider->iWeight*2; + + // Adjust the width by the user specified zoom factor + $fw *= $this->iZoomFactor; + + // Now get the total width taking + // titlewidth, left and rigt margin, dayfont size + // into account + $width = $titlewidth + $nd*$fw + $lm+$rm; + } + else { + $width = $this->img->width; + } + + $width = round($width); + $height = round($height); + // Make a sanity check on image size + if( $width > MAX_GANTTIMG_SIZE_W || $height > MAX_GANTTIMG_SIZE_H ) { + JpgraphError::RaiseL(6007,$width,$height); + //("Sanity check for automatic Gantt chart size failed. Either the width (=$width) or height (=$height) is larger than MAX_GANTTIMG_SIZE. This could potentially be caused by a wrong date in one of the activities."); + } + $this->img->CreateImgCanvas($width,$height); + $this->img->SetMargin($lm,$rm,$tm,$bm); + } + } + + // Return an array width the maximum width for each activity + // column. This is used when we autosize the columns where we need + // to find out the maximum width of each column. In order to do that we + // must walk through all the objects, sigh... + function GetMaxActInfoColWidth() { + $n = count($this->iObj); + if( $n == 0 ) return; + $w = array(); + $m = $this->scale->actinfo->iLeftColMargin + $this->scale->actinfo->iRightColMargin; + + for( $i=0; $i < $n; ++$i ) { + $tmp = $this->iObj[$i]->title->GetColWidth($this->img,$m); + $nn = count($tmp); + for( $j=0; $j < $nn; ++$j ) { + if( empty($w[$j]) ) + $w[$j] = $tmp[$j]; + else + $w[$j] = max($w[$j],$tmp[$j]); + } + } + return $w; + } + + // Stroke the gantt chart + function Stroke($aStrokeFileName="") { + + // If the filename is the predefined value = '_csim_special_' + // we assume that the call to stroke only needs to do enough + // to correctly generate the CSIM maps. + // We use this variable to skip things we don't strictly need + // to do to generate the image map to improve performance + // a best we can. Therefor you will see a lot of tests !$_csim in the + // code below. + $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); + + // Should we autoscale dates? + + if( !$this->scale->IsRangeSet() ) { + list($min,$max) = $this->GetBarMinMax(); + $this->scale->SetRange($min,$max); + } + + $this->scale->AdjustStartEndDay(); + + // Check if we should autoscale the image + $this->AutoSize(); + + // Should we start from the top or just spread the bars out even over the + // available height + $this->scale->SetVertLayout($this->iLayout); + if( $this->iLayout == GANTT_FROMTOP ) { + $maxheight=max($this->GetMaxLabelHeight(),$this->GetMaxBarAbsHeight()); + $this->scale->SetVertSpacing($maxheight*(1+$this->iLabelVMarginFactor)); + } + // If it hasn't been set find out the maximum line number + if( $this->scale->iVertLines == -1 ) + $this->scale->iVertLines = $this->GetBarMaxLineNumber()+1; + + $maxwidth=max($this->scale->actinfo->GetWidth($this->img), + max($this->GetMaxLabelWidth(), + $this->scale->tableTitle->GetWidth($this->img))); + + $this->scale->SetLabelWidth($maxwidth+$this->scale->divider->iWeight);//*(1+$this->iLabelHMarginFactor)); + + if( !$_csim ) { + $this->StrokePlotArea(); + if( $this->iIconDepth == DEPTH_BACK ) { + $this->StrokeIcons(); + } + } + + $this->scale->Stroke(); + + if( !$_csim ) { + // Due to a minor off by 1 bug we need to temporarily adjust the margin + $this->img->right_margin--; + $this->StrokePlotBox(); + $this->img->right_margin++; + } + + // Stroke Grid line + $this->hgrid->Stroke($this->img,$this->scale); + + $n = count($this->iObj); + for($i=0; $i < $n; ++$i) { + //$this->iObj[$i]->SetLabelLeftMargin(round($maxwidth*$this->iLabelHMarginFactor/2)); + $this->iObj[$i]->Stroke($this->img,$this->scale); + } + + $this->StrokeTitles(); + + if( !$_csim ) { + $this->StrokeConstrains(); + $this->footer->Stroke($this->img); + + + if( $this->iIconDepth == DEPTH_FRONT) { + $this->StrokeIcons(); + } + + // Stroke all added user texts + $this->StrokeTexts(); + + // Should we do any final image transformation + if( $this->iImgTrans ) { + if( !class_exists('ImgTrans',false) ) { + require_once('jpgraph_imgtrans.php'); + } + + $tform = new ImgTrans($this->img->img); + $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, + $this->iImgTransDirection,$this->iImgTransHighQ, + $this->iImgTransMinSize,$this->iImgTransFillColor, + $this->iImgTransBorder); + } + + + // If the filename is given as the special "__handle" + // then the image handler is returned and the image is NOT + // streamed back + if( $aStrokeFileName == _IMG_HANDLER ) { + return $this->img->img; + } + else { + // Finally stream the generated picture + $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline, + $aStrokeFileName); + } + } + } + + function StrokeConstrains() { + $n = count($this->iObj); + + // Stroke all constrains + for($i=0; $i < $n; ++$i) { + + // Some gantt objects may not have constraints associated with them + // for example we can add IconPlots which doesn't have this property. + if( empty($this->iObj[$i]->constraints) ) continue; + + $numConstrains = count($this->iObj[$i]->constraints); + + for( $k = 0; $k < $numConstrains; $k++ ) { + $vpos = $this->iObj[$i]->constraints[$k]->iConstrainRow; + if( $vpos >= 0 ) { + $c1 = $this->iObj[$i]->iConstrainPos; + + // Find out which object is on the target row + $targetobj = -1; + for( $j=0; $j < $n && $targetobj == -1; ++$j ) { + if( $this->iObj[$j]->iVPos == $vpos ) { + $targetobj = $j; + } + } + if( $targetobj == -1 ) { + JpGraphError::RaiseL(6008,$this->iObj[$i]->iVPos,$vpos); + //('You have specifed a constrain from row='.$this->iObj[$i]->iVPos.' to row='.$vpos.' which does not have any activity.'); + } + $c2 = $this->iObj[$targetobj]->iConstrainPos; + if( count($c1) == 4 && count($c2 ) == 4) { + switch( $this->iObj[$i]->constraints[$k]->iConstrainType ) { + case CONSTRAIN_ENDSTART: + if( $c1[1] < $c2[1] ) { + $link = new GanttLink($c1[2],$c1[3],$c2[0],$c2[1]); + } + else { + $link = new GanttLink($c1[2],$c1[1],$c2[0],$c2[3]); + } + $link->SetPath(3); + break; + case CONSTRAIN_STARTEND: + if( $c1[1] < $c2[1] ) { + $link = new GanttLink($c1[0],$c1[3],$c2[2],$c2[1]); + } + else { + $link = new GanttLink($c1[0],$c1[1],$c2[2],$c2[3]); + } + $link->SetPath(0); + break; + case CONSTRAIN_ENDEND: + if( $c1[1] < $c2[1] ) { + $link = new GanttLink($c1[2],$c1[3],$c2[2],$c2[1]); + } + else { + $link = new GanttLink($c1[2],$c1[1],$c2[2],$c2[3]); + } + $link->SetPath(1); + break; + case CONSTRAIN_STARTSTART: + if( $c1[1] < $c2[1] ) { + $link = new GanttLink($c1[0],$c1[3],$c2[0],$c2[1]); + } + else { + $link = new GanttLink($c1[0],$c1[1],$c2[0],$c2[3]); + } + $link->SetPath(3); + break; + default: + JpGraphError::RaiseL(6009,$this->iObj[$i]->iVPos,$vpos); + //('Unknown constrain type specified from row='.$this->iObj[$i]->iVPos.' to row='.$vpos); + break; + } + + $link->SetColor($this->iObj[$i]->constraints[$k]->iConstrainColor); + $link->SetArrow($this->iObj[$i]->constraints[$k]->iConstrainArrowSize, + $this->iObj[$i]->constraints[$k]->iConstrainArrowType); + + $link->Stroke($this->img); + } + } + } + } + } + + function GetCSIMAreas() { + if( !$this->iHasStroked ) + $this->Stroke(_CSIM_SPECIALFILE); + + $csim = $this->title->GetCSIMAreas(); + $csim .= $this->subtitle->GetCSIMAreas(); + $csim .= $this->subsubtitle->GetCSIMAreas(); + + $n = count($this->iObj); + for( $i=$n-1; $i >= 0; --$i ) + $csim .= $this->iObj[$i]->GetCSIMArea(); + return $csim; + } +} + +//=================================================== +// CLASS PredefIcons +// Description: Predefined icons for use with Gantt charts +//=================================================== +define('GICON_WARNINGRED',0); +define('GICON_TEXT',1); +define('GICON_ENDCONS',2); +define('GICON_MAIL',3); +define('GICON_STARTCONS',4); +define('GICON_CALC',5); +define('GICON_MAGNIFIER',6); +define('GICON_LOCK',7); +define('GICON_STOP',8); +define('GICON_WARNINGYELLOW',9); +define('GICON_FOLDEROPEN',10); +define('GICON_FOLDER',11); +define('GICON_TEXTIMPORTANT',12); + +class PredefIcons { + private $iBuiltinIcon = null, $iLen = -1 ; + + function GetLen() { + return $this->iLen ; + } + + function GetImg($aIdx) { + if( $aIdx < 0 || $aIdx >= $this->iLen ) { + JpGraphError::RaiseL(6010,$aIdx); + //('Illegal icon index for Gantt builtin icon ['.$aIdx.']'); + } + return Image::CreateFromString(base64_decode($this->iBuiltinIcon[$aIdx][1])); + } + + function __construct() { + //========================================================== + // warning.png + //========================================================== + $this->iBuiltinIcon[0][0]= 1043 ; + $this->iBuiltinIcon[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. + 'B3RJTUUH0wgKFSgilWPhUQAAA6BJREFUeNrtl91rHFUYh5/3zMx+Z5JNUoOamCZNaqTZ6IWIkqRiQWmi1IDetHfeiCiltgXBP8AL'. + '0SIUxf/AvfRSBS9EKILFFqyIH9CEmFZtPqrBJLs7c+b1YneT3WTTbNsUFPLCcAbmzPt73o9zzgzs2Z793231UOdv3w9k9Z2uzOdA'. + '5+2+79yNeL7Hl7hw7oeixRMZ6PJM26W18DNAm/Vh7lR8fqh97NmMF11es1iFpMATqdirwMNA/J4DpIzkr5YsAF1PO6gIMYHRdPwl'. + 'oO2elmB+qH3sm7XozbkgYvy8SzYnZPtcblyM6I+5z3jQ+0vJfgpEu56BfI9vUkbyi2HZd1QJoeWRiAjBd4SDCW8SSAOy6wBHMzF7'. + 'YdV2A+ROuvRPLfHoiSU0EMY/cDAIhxJeGngKaN1VgHyPL7NBxI1K9P4QxBzw3K1zJ/zkG8B9uwaQ7/HNsRZv9kohBGD0o7JqMYS/'. + '/ynPidQw/LrBiPBcS/yFCT95DvB2BWAy4575PaQbQKW+tPd3GCItu2odKI++YxiKu0d26oWmAD7paZU/rLz37VqIijD2YbnzNBBE'. + 'IBHf8K8qjL7vYhCGErEU8CTg3xXAeMp96GrJEqkyXkm9Bhui1xfsunjdGhcYLq+IzjsGmBt5YH/cmJkFq6gIqlon3u4LxdKGuCIo'. + 'Qu41g0E41po+2R33Xt5uz9kRIB2UTle7PnfKrROP1HD4sRjZlq0lzhwoZ6rDNeTi3nEg1si/7FT7kYQbXS6E5E65tA5uRF9tutq0'. + 'K/VwAF+/FbIYWt6+tjQM/AqUms7A4Wy6d7YSfSNxgMmzi0ycWWworio4QJvj4LpuL5BqugTnXzzqJsJwurrlNhJXFaavW67NRw3F'. + 'q+aJcCQVe9fzvJGmAY7/dPH0gi0f64OveGxa+usCuQMeZ0+kt8BVrX+qPO9Bzx0MgqBvs+a2PfDdYIf+WAjXU1ub4tqNaPPzRs8A'. + 'blrli+WVn79cXn0cWKl+tGx7HLc7pu3CSmnfitL+l1UihAhwjFkPQev4K/fSABjBM8JCaFuurJU+rgW41SroA8aNMVNAFtgHJCsn'. + 'XGy/58QVxAC9MccJtZ5kIzNlW440WrJ2ea4YPA9cAooA7i0A/gS+iqLoOpB1HOegqrYB3UBmJrAtQAJwpwPr1Ry92wVlgZsiYlW1'. + 'uX1gU36dymgqYxJIJJNJT1W9QqHgNwFQBGYqo94OwHZQUuPD7ACglSvc+5n5T9m/wfJJX4U9qzEAAAAASUVORK5CYII=' ; + + //========================================================== + // edit.png + //========================================================== + $this->iBuiltinIcon[1][0]= 959 ; + $this->iBuiltinIcon[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAFgAWABY9j+ZuwAAAAlwSFlz'. + 'AAALEAAACxABrSO9dQAAAAd0SU1FB9AKDAwbIEXOA6AAAAM8SURBVHicpdRPaBxlHMbx76ZvsmOTmm1dsEqQSIIsEmGVBAQjivEQ'. + 'PAUJngpWsAWlBw8egpQepKwplN4ULEG9CjkEyUFKlSJrWTG0IU51pCsdYW2ncUPjdtp9Z+f3vuNhu8nKbmhaf5cZeGc+PO8zf1Lc'. + 'm0KhkACICCKCMeaBjiLC0tLSnjNvPmuOHRpH0TZTU1M8zBi9wakzn7OFTs5sw8YYACYmJrre7HkeuVyu69qPF77hlT1XmZ0eQ03O'. + 'wOLJTvhBx1rLz18VmJ0eY+jVd2FxDkKXnvYLHgb97OgLzE4ON9Hzc1B1QaQzsed5O0Lta3Ec89OnR5h5McfQ+Mw2qgQUnfBOPbZ3'. + 'bK3l+xOvMT0+3ERLp5FNF6UEjcL32+DdVmGt5WLhDYYPZrbRqreFumXwql0S3w9tnDvLWD5PZigPpdOwuYpSCo3C8wU3UHxQdHbf'. + 'cZIkNM6dxcnlUM4k1eUFMlUPpUADbpkttFarHe6oYqeOr6yt4RzMQHYUcUsQVtGicHDwKprViuLDkkOtVnsHCHZVRVy/zcj1i5Af'. + 'h8AjdIts+hUcGcYPK3iBtKM3gD/uAzf/AdY2mmmVgy6X8YNNKmGIvyloPcB8SUin07RQ4EZHFdsdG0wkJEnEaHAJxvKEpSLeaokV'. + 'r4zWmhUZYLlY4b1D03y5eIEWCtS7vsciAgiIxkQRabWOrlQor66y4pUphoJb1jiO4uO5o0S3q6RSqVbiOmC7VCEgAhLSaDQ48dH7'. + 'vD46REY0iysegSjKQciRt99ib7qXwX0O+pG4teM6YKHLB9JMq4mTmF9/+AKA4wvLZByH7OgYL7+UY2qvw/7Bfg5kHiXjJFyv3CGO'. + 'Y1rof+BW4t/XLiPG0DCGr79d4XzRxRnIMn98huXSTYyJ6et1UNYQhRvcinpJq86H3wGPPPM0iBDd+QffD1g4eZjLvuG7S1Wef26E'. + 'J7L7eSx7gAHVg7V3MSbi6m/r93baBd6qQjerAJg/9Ql/XrvG0ON1+vv7GH3qSfY5fahUnSTpwZgIEQesaVXRPbHRG/xyJSAxMYlp'. + 'EOm71HUINiY7mGb95l/8jZCyQmJjMDGJjUmsdCROtZ0n/P/Z8v4Fs2MTUUf7vYoAAAAASUVORK5CYII=' ; + + //========================================================== + // endconstrain.png + //========================================================== + $this->iBuiltinIcon[2][0]= 666 ; + $this->iBuiltinIcon[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'. + 'AAALDwAACw8BkvkDpQAAAAd0SU1FB9ALEREILkh0+eQAAAIXSURBVHictZU9aFNRFMd/N81HX77aptJUWmp1LHRpIcWhg5sIDlUQ'. + 'LAXB4t7RRUpwEhy7iQ46CCIoSHcl0CFaoVARU2MFMYktadLXJNok7x2HtCExvuYFmnO4w/3gx+Gc/z1HKRTdMEdXqHbB/sgc/sic'. + 'nDoYAI8XwDa8o1RMLT+2hAsigtTvbIGVqhX46szUifBGswUeCPgAGB7QeLk0X4Ork+HOxo1VgSqGASjMqkn8W4r4vVtEgI/RRQEL'. + 'vaoGD85cl5V3nySR/S1mxWxab7f35PnntNyMJeRr9kCMqiHTy09EoeToLwggx6ymiMOD/VwcD7Oa/MHkcIiQx026WGYto5P/U+ZZ'. + '7gD0QwDuT5z9N3LrVPi0Xs543eQPKkRzaS54eviJIp4tMFQFMllAWN2qcRZHBnixNM8NYD162xq8u7ePSQ+GX2Pjwxc2dB2cLtB8'. + '7GgamCb0anBYBeChMtl8855CarclxU1gvViiUK4w2OMkNDnGeJ8bt9fH90yOnOkCwLFTwhzykhvtYzOWoBBbY//R3dbaNTYhf2RO'. + 'QpeuUMzv188MlwuHy0H13HnE48UzMcL0WAtUHX8OxZHoG1URiFw7rnLLCswuSPD1ulze/iWjT2PSf+dBXRFtVVGIvzqph0pQL7VE'. + 'avXYaXXxPwsnt0imdttCocMmZBdK7YU9D8wuNOW0nXc6QWzPsSa5naZ1beb9BbGB6dxGtMnXAAAAAElFTkSuQmCC' ; + + //========================================================== + // mail.png + //========================================================== + $this->iBuiltinIcon[3][0]= 1122 ; + $this->iBuiltinIcon[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'. + 'AAALEAAACxABrSO9dQAAAAd0SU1FB9AJHAMfFvL9OU8AAAPfSURBVHictZRdaBRXFMd/987H7tbNx8aYtGCrEexDsOBDaKHFxirb'. + 'h0qhsiY0ykppKq1osI99C4H2WSiFFMHWUhXBrjRi0uCmtSEUGgP1QWqhWjGkoW7M1kTX3WRn5p4+TJJNGolQ6IXDnDtz+N0z/3PP'. + 'UWBIpdpYa23b9g09PZ2kUrOrvmUyGVKp1Ao/mUyi56YnVgWfO/P1CihAd/dJMpmaNROIRq8BkM1m0bH6TasC3j6QXgFdXI+DR6PR'. + 'JX/Pno8B+KLnMKqlpUU8z8MYs2RBEDzWf9J+0RcRbMdxGBsbw/fmCXwPMUEYID4iAVp8wIRmDIHMo4yHSIBSASKC+CWE0C/PF9jU'. + '3B6Cp+4M07C5FUtKGNvGwQJctPgIsgD2wRhEIqAMGB+UQYkHJgYYZD7P1HwVlmWhHcfhyk83KeRGUW4t6CgoG5SNUS4KBWgQDUov'. + '7AGlwYASBVqH0Bk49dXpCviVV3dw/tI1Bvr7kMIIlh0NYUpjlF0BAYvcxSXmEVLKceHSCJm+PnbueBHbtkNwTXUNBzo6aGpq4sSZ'. + 'GwT5H7BsF6Wdf1GWHQAoM0upeI9PT1yioS7B7tdaSdSuw7KsUGMAy7HYsmUztTW1nMwM0txssX1rlHjjS5jy/Uq2YkK/eJuLl6/z'. + 'x+1xkslW6mrixGIODx8EFSlEBC0+tmXT0NhA2763iEUjnLv4C8XpUbSbAB1mKkGJ3J83Od77HW5EszvZSqK2iljMIeJaRGNuJePF'. + '6mspY7BJ1DXwQnCd2fxGRq5OUCz8xt72dyhMZcn++Cu3xu9SKhdp2b4ZHWnAtTSxmIWlhcIjlksR3lNBYzlxZsb7+f7ne+xtSzOd'. + 'u83szH1OnThOPp/n+a0beeP1l4mvq+PU2Qyd+5PY1RuwlAqLYFaBfbTbyPSdfgaH77A//QF4f1O/vpr6RJyq+C5Kc/M8FbFxXItY'. + 'xOHDrvfo/fxLDnbsJBp5BowBReVWYAzabeTh5ABDw7cWoNNL3YYYNtSv57lnn6Z+Qx01VeuIuBa2DV1HD3H63BAPZu4u1WGpeLHq'. + 'Rh7+NcjA0O+0p4+CNwXigwnbWlQQdpuEpli+n+PIkcOc//YKuckJJFh2K2anrjFw+QZt6S6kPImIF/b+cqAJD1LihWAxC61twBTo'. + 'fPcQF/oGsVW5ovHQlavs2/8+uYnRVSOUgHAmmAClBIOBwKC0gPjhIRgEIX2wg7NnwpZW3d3d4vs+vu8TBMGK51rvPM9b8hdteZxd'. + 'LBbVR8feJDs0Rlv6GFKeXJ21rNRXESxMPR+CBUl0nN7PjtO+dye7Up/8v1I88bf/ixT/AO1/hZsqW+C6AAAAAElFTkSuQmCC' ; + + //========================================================== + // startconstrain.png + //========================================================== + $this->iBuiltinIcon[4][0]= 725 ; + $this->iBuiltinIcon[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'. + 'AAALDgAACw4BQL7hQQAAAAd0SU1FB9ALEREICJp5fBkAAAJSSURBVHic3dS9a1NRGMfx77kxtS+xqS9FG6p1ER3qVJpBQUUc3CRU'. + 'BwURVLB1EAuKIP0THJQiiNRJBK3iJl18AyeltRZa0bbaJMbUNmlNSm5e7s25j0NqpSSmyag/OMM9POdzDuflwn8djz8gClVRrVEV'. + 'ur4Bl1FTNSzLrSS6vbml0jUUwSXj8Qfk3PkLtLW2AeBIybmrgz3+gFzpucjlE4f4btuFTuWuCF5XDr3a3UPf6cM8GQvxzbsRAJdh'. + 'ScfxSywml5j7mVypN0eGEJ0tebIre+zxB6Tv7jPReS2hREpOvpmUXU+H5eC913JnNCSRVE60pUVbWoZjprR39Yq70bdqj4pW7PEH'. + '5FpvL9e79jOTTHM7ssDL6CJZ08LbvAGnrpZg2mI2Z/MlZfN8IkxuSwu4V9+WIrj7zFlOHfXzKrLIi2SGh5ECKjnNVNxkQEc55vOw'. + 'rb6O8JLFdHyJ+ayFElUeHvjwkfteL/V7fKTSkFvIQE4DoLI2Mz/muTkTApcBKIwaN8pwIUrKw+ajWwDknAO0d/r4zFaMuRS63sWm'. + 'RoOdm+vRIriUYjKexrQV+t1o0YEVwfZSVJmD/dIABJuO0LG3lRFx0GOfiAELE9OgCrfU0XnIp5FwGLEy5WEAOxlR5uN+ARhP7GN3'. + '5w7Gv4bQI2+xpt4jjv2nWBmIlcExE2vDAHYioszBZXw6CPE4ADoWVHmd/tuwlZR9eXYyoszBfpiNQqaAOU5+TXRN+DeeenADPT9b'. + 'EVgKVsutKPl0TGWGhwofoquaoKK4apsq/tH/e/kFwBMXLgAEKK4AAAAASUVORK5CYII=' ; + + //========================================================== + // calc.png + //========================================================== + $this->iBuiltinIcon[5][0]= 589 ; + $this->iBuiltinIcon[5][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAA4AIwBbgMF12wAAAAlwSFlz'. + 'AAALEQAACxEBf2RfkQAAAAd0SU1FB9AHBxQeFsqn0wQAAAHKSURBVHicnZWff+RAGIef3U/gcOEgUAgUCgcLhYXCwsHBQeGgUDgs'. + 'FgMHB4VA/4Bg4XChWFgIFIqBwkJhsRAYeOGF+TQHmWSTTbKd9pU37/x45jvfTDITXEynAbdWKVQB0NazcVm0alcL4rJaRVzm+w/e'. + '3iwAkzbYRcnnYgI04GCvsxxSPabYaEdt2Ra6D0atcvvvDmyrMWBX1zPq2ircP/Tk98DiJtjV/fim6ziOCL6dDHZNhxQ3arIMsox4'. + 'vejleL2Ay9+jaw6A+4OSICG2cacGKhsGxg+CxeqAQS0Y7BYJvowq7iGMOhXHEfzpvpQkA9bLKgOgWKt+4Lo1mM9hs9m17QNsJ70P'. + 'Fjc/O52joogoX8MZKiBiAFxd9Z1vcj9wfSpUlDRNMcYQxzFpmnJ0FPH8nDe1MQaWSz9woQpWSZKEojDkeaWoKAyr1tlu+s48wfVx'. + 'u7n5i7jthmGIiEGcT+36PP+gFeJrxWLhb0UA/lb4ggGs1T0rZs0zwM/ZjNfilcIY5tutPxgOW3F6dUX464LrKILLiw+A7WErrl+2'. + 'rABG1EL/BilZP8DjU2uR4U+2E49P1Z8QJmNXUzl24A9GBT0IruCfi86d9x+D12RGzt+pNAAAAABJRU5ErkJggg==' ; + + //========================================================== + // mag.png + //========================================================== + $this->iBuiltinIcon[6][0]= 1415 ; + $this->iBuiltinIcon[6][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'. + 'AAALDAAACwwBP0AiyAAAAAd0SU1FB9ALDxEWDY6Ul+UAAAUESURBVHicdZVrbFRFGIafsyyF0nalV1R6WiggaAptlzsr1OgEogmC'. + '0IgoBAsBgkIrBAPEhBj/AP6xRTCUFEwRI4jcgsitXMrFCJptJWvBNpXYbbXtbtttt6e7e86ec/yxadlCfZPJZDIz73zzzjfvR2VL'. + 'F7U+hf0HD2JduIzTFy6SlJRkPtkcDgdCCE65OxFC8NPV6wghyM7OptankJ2dzbSC5QghEEIgCSHog9PpNAF27dlN6miZuPgElB4/'. + 'nmY3O7ZtByA1NVUCkGWZweD1eklJScESTbqxuIjrd+/x6uIl5M19hSy7nfGOeUxf+g7VjU1sKi7C4/GYsiyz7tAJAD4/cRaA1tZW'. + 'AHIPnECUVGD1+/3U19ebG4uLeHf1akamjsIwoVnVCOvQEdLoVILYYmMo3PIxSBJflpSaDX5FAmju1QAYv/8k/s8+wLVxOU0jR2LZ'. + '8sMFAApWrCApbRRDrRZirBYSLBKaoRPQw3SFernf2sav7T0Ubt4KwL4FMwF4Vu8FoHBCKgCzDhwHwLIhZ7y5a89u4m2JhA0wTdDC'. + 'OrphEjJMNElCHxKDEjaobmvlfo/Krj27CQQCJsCGJW8C0KXqAMxMiosQA8hZWcTFx9OsaniDKh1qmG7VoFsL0x0K06kbeAMhWpRe'. + '/KpG+gwHAKUnz7Dz3BUMw6DK18nuw99wt0Nh6VdHI8RJicmETQgFg7SFwjSrGv+oKp6ghldV6dZ0ugJBlF6FmCESQ2w2AIqXLsan'. + 'BrFYLJTnTCBrdBqveeopWZiPFaBHUegJhegMqGgxEkHDwB/UaQ9rdIV06v0+TD2EEQjQFtAY0dsNgNvt5sialQAIIXh7wQKuVf6J'. + 'gTsSccPDWlQstClBGjr9eHpVWvUQncEwdYEedF8noQ4vmYmpZMTH0nTvDn25vLbrNmu7bvfnsYEbAMnhcPDgwQPzUo2LJusw/mhp'. + 'QwlHNO0KBAnoIfxtrcQMT2De1Mm891wyUzNlUlJSpIyMDBobGzlzr5rFM/Koq6vrP8ASGxsLwPmKcvIShjPGZiPOakE3VFB8hHwd'. + 'vJAxhrk5L7Ly+RQuH/sWgPdXrwFg/6HDFBUsIj09nehfbAWwPWOT9n5RYhqGwarNWxkRM5TRCfF4U1PQsDDJFk9uYhwXvzvKjm3b'. + 'KSsro3DJInNW5RXp7u2bAKSlpeH1esnPz6eqqgqLpmmcr3Fht9ulfaV7mZk1Bs+lM6T1djM9fhg5egDPpTNMy5TZsW07kydPYdWM'. + 'aXx96ixOp9O8cfUa80srmDpjOgAulytiQqZpMnvObLbt/JTtHxXj9/tRVdU0DGOAufRpevPDTeac0hJyc3NxOOawfv161lVWS6eX'. + 'z+9/UOCxu1VWVvaTRGv16NFfjB2bNeAQp9NpTpmSM4DcbrdL0WsGDKLRR+52uwe1yP8jb2lpYfikyY9t80n03UCWZeaXVjw1f+zs'. + 'Oen+/d+pqanhzp2fKSsrw+l0mi6XiyPl5ZGITdN8fAVJwjRNJEmi1qfw1kw7siyTnJxMe3s71dXV3GpoZO64DG41NPJylvxU5D/e'. + 'qJKsfWQD9IkaZ2RmUvr9aV4aGYcQgjfO3aWoYBF5eXm4ewIsu/CbdPz1aWb0/p1bNoOrQxlUiuiaFo3c3FyEEOx9+C9CCD6paaTW'. + 'p/TXyYkTJ0Xe59jf7QOyAKDWp/QXxcFQ61P4pT3ShBBcvnUHIQTjxmX19/8BCeVg+/GPpskAAAAASUVORK5CYII=' ; + + //========================================================== + // lock.png + //========================================================== + $this->iBuiltinIcon[7][0]= 963 ; + $this->iBuiltinIcon[7][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'. + 'AAALCwAACwsBbQSEtwAAAAd0SU1FB9AKAw0XDmwMOwIAAANASURBVHic7ZXfS1t3GMY/3+PprI7aisvo2YU6h6ATA8JW4rrlsF4U'. + 'qiAsF9mhl0N2cYTRy9G/wptAYWPD9iJtRy5asDe7cYFmyjaXOLaMImOrmkRrjL9yTmIS3120JybWQgfb3R74wuc8Lzw858vLOUpE'. + 'OK6pqSm2trbY39+nu7tbPHYch7m5OcLhMIA67kWj0aMQEWk6tm17rNm2LSIie3t7ksvlJJ1OSyqVkls3Z8SyLMnlcqTTaVKpFLdu'. + 'zmBZVj1HeY2VUti2TSQSQSml2bZdi0QirK2tMT09zerqKtlslqGhISYnJ4nHv2N+foFsNquOe9FotLlxOBwmk8lgWRbhcFgymYxY'. + 'liUi0mqaJoAuIi2macrdO7fFsizx3to0Te7euV1vrXtXEgqFmJmZYWVlhXK5LB4/U9kwDL784kYV0A3DYHd3m4sXRymXywKoRi8U'. + 'Ch01DgQCJBIJLMsiEAhIIpHw2uLz+eqtYrEYIqKZpimxWEyCwaCMjY01zYPBIJpXqVQqsby8TLVabWKA/v5+RkZGMAyDrq4ulFKH'. + 'HsfjcWZnZ+ns7KTRqwcnk0mKxSKFQqGJlVKtruuSTCYB6O3trW9UI/v9/iZPB/j8s2HOnX0FgHfeXpeffnzK+fWf+fijvhLs0PtG'. + 'D/n1OJ9+MsrlSwb3733DwMCAt1EyPj6uACYmJp56168NU6nUqFSE9nZdPE7+WqC/r4NKTagcCJVqDaUUB5VDAA4Pa9x7sMLlSwan'. + 'WjRmv13D7/erpaWlo604qOp88OF7LC48rPNosMq5Th+Dgxd4/XyA1rbzADi7j8jnf2P++wdcvSr8MJ/i8eomAKlUqn41OsDAQDeD'. + 'g++yuPCwzm/2vU8+n2a7sMFfj79mp7BBuVzioFSiXHJx3SKuW2Rzy0Up9dxnQVvODALQerqNRn4ZKe0Mvtc6TpzpmqbxalcY9Ato'. + '2v06t515C73YQftZB9GLnDrt4LoujuPgOA4Ui+C6yOpXJwZrJ7r/gv4P/u+D9W7fLxTz+1ScQxrZ3atRLaVxdjbY2d184R6/sLHe'. + 'opHP7/Do90Ua+WWUyezzZHObP/7cfX54/dowE1d66s8TV3oE+Mfn+L/zb4XmHPjRG9YjAAAAAElFTkSuQmCC' ; + + //========================================================== + // stop.png + //========================================================== + $this->iBuiltinIcon[8][0]= 889 ; + $this->iBuiltinIcon[8][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'. + 'AAALDwAACw8BkvkDpQAAAAd0SU1FB9AJDwEvNyD6M/0AAAL2SURBVHic1ZTLaxVnGIefb2bO5OScHJN4oWrFNqcUJYoUEgU3/Qf6'. + 'F7gwCkIrvdBLUtqqiLhSg9bgBduFSHZdiG5ctkJ3xRDbUFwUmghNzBDanPGMkzOX79LFJGPMOSd204U/+Bbzvd/78F4H/ieJdoad'. + 'pZKxRFszAI/DcP0HazXY22v+HB01kee1PA/v3zfnjx4xgGnHcNZe7OvuNj+cOEF1ZATv5nUA4jhBSgmADCVWo8Ge2Of9wb18P/G7'. + 'oUXmYi30zqlTVEdGWLh1g2D6MYlKkXGE0Vl8aa2GEB149+4xXSzyoOIw/mimiZV/DPb25pFOj13A9gOMEChhUEqhVYqWKUk9QAUp'. + 'sT/P4s8PmKlUmNhQaIJbkDVqBbpw6wZ2zUc4Nm+ePku5p4eOrgpueQOFUoVCVxcD4+N07dpF9+5tVJeWGPBjhvr7WF1zC8ASgtcP'. + 'H8a7eZ1odh4sh50nzwCw9ZNh3M4Stutiu0X2nB/LyjZ6lcIbVTpdQU/jWVPzLADM8+ZGBRdtC7wrF/O7bR99iu26VL86iU4SAH4b'. + 'Po5d6AQhstMSvGyI4wS5FJBKSRwnzF8byx/u+PjzzMF1mfryQ1K/jnCahqp1xEopjFLoNEFJSRJHzF799gWHqa+/QKcSUXBI609f'. + 'Al5W4teQSiHDOipNUKnMI13RvnOXAIEKQixvGWya98SC560MFwPiqEG86JM8q79Q06lvhnOndy5/B6GPCUOMUu3BQgg8z0M3GmBZ'. + 'iGJn3v2VmsqnfzNx7FDueODuj8ROCFpjtG5TCmOYv32bJ09msP0ISydMfnAUgF8/O45RAA6WTPjlvXcB+Gn7FuRf/zAnNX6x3ARe'. + 'PSdmqL+P/YHkwMGDOGWDZTlQcNBRhPEComgB/YeHfq2InF1kLlXUOkpMbio1bd7aATRD/X0M1lPeSlM2vt2X1XBZjZnpLG2tmZO6'. + 'LbQVOIcP+HG2UauH3xgwBqOz9Cc3l1tC24Fz+MvUDroeGNb5if9H/1dM/wLPCYMw9fryKgAAAABJRU5ErkJggg==' ; + + //========================================================== + // error.png + //========================================================== + $this->iBuiltinIcon[9][0]= 541 ; + $this->iBuiltinIcon[9][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAaVBMVEX//////2Xy8mLl5V/Z2VvMzFi/v1WyslKlpU+ZmUyMjEh/'. + 'f0VyckJlZT9YWDxMTDjAwMDy8sLl5bnY2K/MzKW/v5yyspKlpYiYmH+MjHY/PzV/f2xycmJlZVlZWU9MTEXY2Ms/PzwyMjLFTjea'. + 'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTCAkUMSj9wWSOAAABLUlEQVR4'. + '2s2U3ZKCMAxGjfzJanFAXFkUle/9H9JUKA1gKTN7Yy6YMjl+kNPK5rlZVSuxf1ZRnlZxFYAm93NnIKvR+MEHUgqBXx93wZGIUrSe'. + 'h+ctEgbpiMo3iQ4kioHCGxir/ZYUbr7AgPXs9bX0BCYM8vN/cPe8oQYzom3tVsSBMVHEoOJ5dm5F1RsIe9CtqGgRacCAkUvRtevT'. + 'e2pd6vOWF+gCuc/brcuhyARakBU9FgK5bUBWdHEH8tHpDsZnRTZQGzdLVvQ3CzyYZiTAmSIODEwzFCAdJopuvbpeZDisJ4pKEcjD'. + 'ijWPJhU1MjCo9dkYfiUVjQNTDKY6CVbR6A0niUSZjRwFanR0l9i/TyvGnFdqwStq5axMfDbyBksld/FUumvxS/Bd9VyJvQDWiiMx'. + 'iOsCHgAAAABJRU5ErkJggg==' ; + + //========================================================== + // openfolder.png + //========================================================== + $this->iBuiltinIcon[10][0]= 2040 ; + $this->iBuiltinIcon[10][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEANAAtwClFht71AAAAAlwSFlz'. + 'AAALEAAACxABrSO9dQAAAAd0SU1FB9AKDQ4RIXMeaLcAAAd1SURBVHicxZd7jBXVHcc/58zcvTNzH8vusqw8FsTsKiCUUh5WBZXG'. + 'GkOptmqwNWsWLKXFGlEpzZI0AWNKSy0WhDS22gJKtWlTsSRqzYIuLGB2WVvDIwQMZQMsy2OFfdzde+/OnHP6x907vJaFpjb9JZM5'. + 'c85Mfp/f9/s7Jxn4P4e41gtSyp78WGvtfdEAcqDFYUOH9HS0NhGk9tPb/ilSyp789UUB2AMuqhQy3Uzm7HGkE6W3dTNZMRI3EcWO'. + 'jf9ClLmWBT3dzW8jUsevWHCG3UpWl+IkHSxnbDh/Mcz12NevBcuWXTmf6TjnXvJ88gDmVB3pw3+nt3UzHa1NqMzBS2zqPLGFjtMN'. + 'ZNr3XdW+qyqwZcFk76HX/tHWfuQvyO4W7qhaHwL8efkMRlRUpPv7rqD0RrJ+FgAjLy1a20OIxZJEEuNCRfIApj+om4bGM3u2/sYU'. + '9J41d8973f3Dhg1pISTV1dXXBRNJxPGFCzhou+DCQrScZOkktNaeDZjamgeZ9MgiYmVDccvHhjAzJw0NTh8/alyZMaVJicp0iTHj'. + 'JpgNv38tjWUhhGROdbUL9W5/MH5XCkjlcibi+KIop5LVHLKEu8A/f4r286doa9pGrGwYAAsfqbbH3b8MgO/Nqgy6WvdbbXHMkEFJ'. + '4xUOMVEvaTZu3BgmvF4Yk4hz9rO/Ulr5cE9owae/rcGxohSOuiWkC2IjcIqKyPZm+OmCH7GhoZEF077EEzVVweAbJ+riEeO0Ey8y'. + 'UubqOHn0AOgMwvf59txnBrSp9dgxKmf/+kIP1NY8SFk0jh5ajmNHAWg5b2E5EexojGHjbiVRMoRMNs0LC+Yz46vTuH3enN7BI8fr'. + 'qFdo0BoVZNC9aVSQ4fNjBzEmQJiARxb+/AqYPMAVB5FsPU5v37g9OxgLhe14ZM5/ju052E6MNZvf5pmHHuLmmWOkEysxUtpGAtme'. + 'dtHTflJkezqQto3jFRnLssyf1jydxiiM7zNnye/c3ZsqLu2BN5fcMfzrv/hby1tPzmRUoihcTJ87CwQI2yLtDcIqsIjYUf51qBlf'. + 'OnScOSrdQUOMURkiXsLUzJnvbGhoBGDHH5cGyZLhOpYoNl5hqYnYEXOu5fDl9eYAHntx98n8hFHZcPHUuTSxSASAeK/CGIOxJJ0f'. + 'bOGNPU280dgkq6Y2yu8vfjCIlwwzr+/ZQ/PHO0gOLuO5qsftDQ2NbN+4OCgqG6WTxWVaq6zpF+DiSHWnicdylp3r6aZTWthIOrNp'. + 'ktHcvBu0sHX1Sm6ozB3B42d90zZA9bQp7PvgPSzXZfnqX/HS4DKKK2+x69Y/HURs26iBAN5ccsfw7774UcumF37C6f07KSt2OHji'. + 'DEUJD0tISjyPrrSPlAKvN0JP/U4O1NfjuhG2rvklN1SOpfXwftpbTqAyKRrff5fb7rs9V1R7m4wlz2ihA3HpmXflUWyOH2umpLiY'. + 'ui3v8M+6bWzfsRNbSgqkxaCkiy0simMuEWEhpcRzIhQWOIAh6tiAwS4owInFiTou5dOnMnl2NR++ujBwXEc9terD6M43nrj6LgAB'. + 'QnDPA9/irtkP8JRS7Hr/3T6YekDQ1pEiEXOwpUVJzCVlZZFS4mZtkpEo9ChAkDp/jtLMBACy6S4RiQghLyv5cgBRPnKUOX6smUGF'. + 'hSil0MYw9d77mPy1e5mnFE3batm3czvb6nYgEJztSFGU9LCRlMRdUjIH0+lnEMIwPNXD3NumoVJnrMCJaiciMUZfvQnz4QcBSvV1'. + 'vjE5GK358t0zmXDnDB79saLpo20c+aSRD+t25JTp7GZQwsEWFiVxl6hlUf/WO9z32CxmL1rOe6u/I2KuwGhzLQCB7/sYY9Bah3el'. + 'FKbvrrVm4vS7GH/7ncx+chEHGz7myCeNbPtoO0JI2jq78WIRLGkzsqs7V5SfFV5EovXACoiqqsfNpk2vo5VCWtYFBfoU0VoTBAFa'. + 'a7TRaK2p+MoURk+cxMzq+Rzbv49DDbuo27UTW9h0dedssPxuK+kIfN8XxhgDYPVXf2Fh4XKtFIl4AiklAlBKAYRKKK36wHIweTCt'. + 'NfHiEkaOn8j0+7/BmDFjaT30GbHywSxcuZkpFfFg+m1jjZ/NmnVvNfRvwd69e8WBA/uNFAIh4JVXXmHsmDHE4vEQQgjQ2lxQIm9N'. + 'nz35q3BEOZOHzaG2thaA4mRU+L29It+IV21CpbRQfeMFC35gRB/M2rVrubnyZmLxWJhECBEmz/eHyo/7lMlH3LFFujsthNFCCGOu'. + '+WNyeUgpjSVzMKtWraKyshLPdcPEeYWCIEBdpIxSivr6eta8vI7d6+cGnhdV06pe1QP+F/QXWmuRL+jZZ58LlVmxYgUVFRV4rhtu'. + '4TzMxXAA6XRaRAtsYUkx8I/JtSJQOlSwpmZpCLN8+fPcdNNoHMfB9/0QJgRoP295TlR7UVv8xxZcHMuWIZ9/Hn35vG3JEGZpzVJG'. + 'jx5N1IlitKahsZE1L69j69qHgx+urFX/lQL9JYdLlfnZihUhzOLFi8N3Ml1dthOxVH/f/8/CtqSJ2JaJ2JZ59J7RPsC/AViJsQS/'. + 'dBntAAAAAElFTkSuQmCC' ; + + //========================================================== + // folder.png + //========================================================== + $this->iBuiltinIcon[11][0]= 1824 ; + $this->iBuiltinIcon[11][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'. + 'AAALEAAACxABrSO9dQAAAAd0SU1FB9ECAQgFFyd9cRUAAAadSURBVHiczdhvbBP3Hcfx9/2xfefEOA5JoCNNnIT8AdtZmYBETJsI'. + '6+jQOlQihT1AYgytqzZpD1atfyYqlT1h0lRpT7aRJ4NQpRvZGELVuo5Ua9jEJDIETQsNQyPBsUJMWGPnj//e+e72wNg4xElMR6ed'. + 'ZNln3933dZ/f93f6yfB/sgmrHdDV1WXlPg8NDZUDScD8LFFFEZZlWYZhWMFg0Orq6sq/gDJAfFy1iiZy9OjrVnj4JzQ1rMWqfxm/'. + '309jYyNtbW0kEgnu3bvH4cOH88c/jqSKQl4/XGkd+eVtAN46up1LH92ktqYS++ZX8Pv9NDQ0sGnTJlKpFOFwmO7u7vy5IyMjeVRd'. + 'XV1+WEOh0IrY4pDnq6wXX/sTiCJaMkFZdRNqxefoe7VtCSqXVDqdZnZ2ltraWkzTpKqqijt3JpFlG7dvj7NzZ1f++qFQyA3EClHL'. + 'Ql743nFkhxPDtJAd5eTaYSVUfX09lZWVlJWVIUnSg7sVQMBCUcu4ceMGe/bsIRQK1QAzOcyykIM9P0KyudAyCWyqG8nhwqa4SkLt'. + '3r0bVVVxu924XC40TUOWZUQxe97CwgIdHR2LMHIxSCaVInVvFElxE0vMY1Pd2NUKJMWNTXHlUfF//4vETJCelwbpFm3MjP2dt37x'. + 'AlN+PzU1NViWRSwW4+7du3g8HjweD4qi5EFAJzAExIpCANbooxhplfB0FJvTg6xWIqsVRVF6MopkU3FXPcnkJxGU0VEAdF2noqKC'. + 'W3/8DpnqLjzep2lubsblcjE8PExHR8fboVDID9xYFpLBDpJF0jDQIncQpWlkm31FlFLtp9PfyuW/vYQj1kPSuRW/38+lj27S2Q7v'. + '/aWXUBVUffVNtm3blivVCEwsC5Eyc5iiApEpDEAXMqQdldhSiWVQHjJagud+8Fuexck/zv+K82dfoSbSCsDe75/km+4GVPd6+l5t'. + '4zJHcqVUYN2yEEtZQDCSJCueRAYsPY49HsFIZVG6p25JUumFafT4DKJN4amtT7Nz38sk5+5A70HMtEYyMkFiZhxzjQ/poXrLQrRU'. + 'DFGEeFpAlkQkm4pRiCpIKodKzk0T/2QMh+piPjxKZPwiSkUtu/b9mNnJEWS7E8nhAmvpM60oJDkXJxqNozxRRUxPIesispBBlsXV'. + 'UaKEFo8gzoaJhz8s2lOmrpUG+WBhJ9/60g+Z+fDXTAXfxllRjl1VkO0OFATsYhYliiK21ZKKhhHnFveUqSdKgwAEOp7F2v51vvw8'. + 'XH7/N1wd/BlTweuUV65BdtgfoLTSkipsdD3tRi0VYpommUwGwzDwdT5HYEc3giAwcvH3jLz3BlPB67jWeZBEKYsSBWwpHZtNKo4q'. + 'aHTDsJeeiGEYWJaFZVmYpommaRiGQdPnv0bb1m8gSRL/vPIOV979aR4lmAJ2p4qCgCxksNuKJ6VNpx4NYhgGpmkuQhmGQTqdxjAM'. + 'qr2d7HtxEEEQuH1tkKvvvkF44tqDnrIcKJKAPf1g+LAUElq8dIiu60sApmnm93Pfzc7OYhgGrie+wFe++ztcLhcT1wf54PzPCU9c'. + 'w7XWjWS3IdsdOAUBWZAxrRJnTQ6SG5bce2FCpmkughmGQSqVYm5uDtnj44sH38TtdhP6+Dwf//V4ttHXrkGURZJaic8RgHQ6jWma'. + 'SJKUL5RLKNfIOczDKF3XSSaTRCIRhLJWntp3nGfWrSMxc5OLf3iNP4+68T9Ub9nF76lTpxgfHycajZJKpdA0LZ9GbjYV7hcDWZaF'. + 'pmnMz88Ti8UYunSLmu1HFi2aVkxkaGjINTY2ttDb24vX6+XQoUNs3ryZ8vJyIDu1BUFYkkxhgxeiWlpaOHPmDE1NTdTX1xe98eWG'. + 'JnF/9dQZCoXUYDA4AOD1ejlw4ACtra2Ul5fniwmCkEcUJiUIAoFAgL6+Pnw+H21tbfT39z8SxCS7hHsfWH9/8dL4MKqnp4eWlhac'. + 'TmcekEvMNE2am5s5ceIEgUCA9vZ2Tp48ic/nY3j4UsmQHCYOjJHtpeBKqL1799Lc3IzT6UTXdRobGxkYGKC9vZ3W1tZ8Ko86NJ8a'. + 'tXHjRo4dO8bp06fZsmULGzZsoL+/n0AggNfr5ezZs/8VpGTU5OSkc//+/acBfD4f1dXV7Nq1i4aGBs6dO4fP5+Pq1SuPBbIiyjTN'. + 'RUnV1dUNXLhwAa/Xy44dO4jFYgBEo9FFF1r134BPuYlk16LrAYXsAlmtq6sbKDwoFAp9m+ykuP5ZQVZF3f8tCdwCov8LyHIoAANI'. + 'AXf/A1TI0XCDh7OWAAAAAElFTkSuQmCC' ; + + //========================================================== + // file_important.png + //========================================================== + $this->iBuiltinIcon[12][0]= 1785 ; + $this->iBuiltinIcon[12][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'. + 'AAALDwAACw8BkvkDpQAAAAd0SU1FB9ECDAcjDeD3lKsAAAZ2SURBVHicrZhPaFzHHcc/897s7lutJCsr2VHsOHWMk0MPbsBUrcnF'. + 'OFRdSo6FNhdB6SGHlpDmYtJCDyoxyKe6EBxKQkt7KKL0T6ABo0NbciqigtC6PhWKI2NFqqxdSd7V2/dmftPDvPd212t55dCBYfbN'. + 'zpvfZ77z+/1mdhUjytWrV93Hf/24eD5z9gwiMlDjOKbb7dLtdhER2u02u7u73Lp1CxEZBw4AeZwdNQqkMd9wbziFGINJUt6rRbz5'. + '1ptUq1XK5TJBEAAUMHt7e+zu7gKwvLzMysoKwAng/uNg9CgQgFKlgg1DUJ67Vqtx6tQpZmdniaIIpRTOOZRSdDoddnZ2aLfbLC8v'. + 's7S0xJUrV7ZGwQSj1PhhfRodVdDlMrpc5vup5Z2fvMPdu3fZ29vDWjvwztjYGPV6nVqtRqVS4dKlSywtLQFsAdOH2XwsCEApg3jl'. + 'w98Rak2gvYjNZpNms0mSJDjnHgkDMDc3dySYQ0Ea8w139YUX0OUKulzyg7UmCEO+l1huvHuDra0t9vf3h1TJYSqVypFhHquIrlQI'. + 'S5qv/uIDAC7/4bcEQYAKvK+0Wq1DVQGIoog7d+4cCeaRII35hrt+8SsEOkRlUaEyR0UpFIrXHxyMVKVUKnHv3r0jwRwaNelBjBjL'. + 'Sz/7KYuLiwAsLi7y4z/9kY9e+TpkCuSqjI+Po7XuAWeKXLt2DWNMUZMkwRjDhQsXWFtbK6JpCCT3jfQgxomPtPX19YHWicM5x3c2'. + '73Pj3Ru8/aO3mZqaolKpoHVvyuvXr/Ppnf/Q7uzz380NPtu4y/qnG+ztd1hfX2dtbQ3gIvDnRyqSxl1UoPjyz98D4PTp0wPtq39Z'. + '4fdzLxegrVaLVqvF5OQkYRgWqpRKJZ77wvNsbW1RG5tgfKLOTH2G7Z1twqBQrgrMDvhInjfSOCY5iIv+hYWFgRZArEWsZWF941Bf'. + 'SdMUgMnJCWpjVU4cn+HUyePM1Gc4+fRUPkzBI5w1jbukcczLv/5l0XfmzJmBFuCba38r/CRXpT+CrDUoZ0jjB4RYonJAOYRobJKT'. + 'z5zgqfqxAbsFSH6mpHFM2qdGXh4VnoViD6mSJF2cTQeqDqBaKVHWmonJCWpZjhkC6anR5WsffTgwaHV1FaUUq6urA/2v3f5k4LnV'. + 'arG9tUn3oI2YBCcWHYAxMVYs1qZEZY2SFB2aYZDGfMN9d7uJiWPSeFiNo5Rclc3NTXZbO6RpF7EJVixYA9agwwDnUiqlEPdQ3imi'. + 'Jo27BGHIt/7x9yEjc3Nzh27Na7c/4TdffKl4bja3ae5MUIu0T/HOEIaOpJt4gwoSsVTK4SBIY77hFtY3ABBjBiZ90rKwvsH77/+K'. + 't37wOhO1iPpTk4SBw1mLsz6CnKQ4l3qV+kE+t9XHlNZOk+bUJLVIE1VCcIJWQmJ6qjj30NbcXLkZMt8YPig+Z3n1G5fZ39/j/vY2'. + '9ckqZT2Ochbn0p4qNkU/dDfUADdXbh4HXgRO4zNdEU0XL1784PLly5w9e7Z4SazFOfGrEotDcOKrcoJPmrYIXf/Zop3QNd1skuGt'. + 'cUAb2MgAxvHZTgFUq1Wmp6eZnZ0F8JlTjDduDThBnDeECEoJtbGIp6enqEblzCcEZ1PECU4yVRiOGgd0gc+AB0CZvkv1sWPHOHfu'. + 'HOfPn8da41cpkkltEBEPJhYnBkTQJcdYVKGkgRxCfBsq5xXNgAa2Bn+hjTOgHEKBP8pzRUxykIH4ifLJRTJAl+UMBJzPHQ6bfe/f'. + 'cWIzPxlUpD+zugzIZtVk1d8znBAqRxgoQuVQgSJQ3h9C5QhDRYgjUILCAzlnEdsHYTKfMTEBcP7F54YUGVmc2GLlIn6ve6v0ahSt'. + '8X25TzjJ+rIx1grKpQPWR4LkGVVsMgghvS0qjPdvm5OeceOTWA5Evo2mFzkjQfL7hZPUy5yvvF/uPFQL3+nbDmsLCEmT3sTmCTNr'. + 'rogT6yFsOix3ftw7OwQhkvSU6CuinhCk0+kAkFoBazEEICHaHHiPVmU0gnUp4EAc1mYrF0EBVpwPi34VrBkwPxKk3W5ju/e5/c+d'. + 'bGUHIAIuydTIE5zfc5Wr4lJcahHnHTP3CVGm78DrgY38N+DEibp7dmYKdAQmBh1hjEFjis+9CTWYGK21H6PxPyOI0DobYwzZF/z7'. + '7jadTvJtYG0kCD7lfwl49ijgT1gc0AH+dZSJA/xB+Mz/GSIvFoj/B7H1mAd8CO/zAAAAAElFTkSuQmCC' ; + + $this->iLen = count($this->iBuiltinIcon); + } +} + +//=================================================== +// Global cache for builtin images +//=================================================== +$_gPredefIcons = new PredefIcons(); + +//=================================================== +// CLASS IconImage +// Description: Holds properties for an icon image +//=================================================== +class IconImage { + private $iGDImage=null; + private $iWidth,$iHeight; + private $ixalign='left',$iyalign='center'; + private $iScale=1.0; + + function __construct($aIcon,$aScale=1) { + GLOBAL $_gPredefIcons ; + if( is_string($aIcon) ) { + $this->iGDImage = Graph::LoadBkgImage('',$aIcon); + } + elseif( is_integer($aIcon) ) { + // Builtin image + $this->iGDImage = $_gPredefIcons->GetImg($aIcon); + } + else { + JpGraphError::RaiseL(6011); + //('Argument to IconImage must be string or integer'); + } + $this->iScale = $aScale; + $this->iWidth = Image::GetWidth($this->iGDImage); + $this->iHeight = Image::GetHeight($this->iGDImage); + } + + function GetWidth() { + return round($this->iScale*$this->iWidth); + } + + function GetHeight() { + return round($this->iScale*$this->iHeight); + } + + function SetAlign($aX='left',$aY='center') { + $this->ixalign = $aX; + $this->iyalign = $aY; + } + + function Stroke($aImg,$x,$y) { + + if( $this->ixalign == 'right' ) { + $x -= $this->iWidth; + } + elseif( $this->ixalign == 'center' ) { + $x -= round($this->iWidth/2*$this->iScale); + } + + if( $this->iyalign == 'bottom' ) { + $y -= $this->iHeight; + } + elseif( $this->iyalign == 'center' ) { + $y -= round($this->iHeight/2*$this->iScale); + } + + $aImg->Copy($this->iGDImage, + $x,$y,0,0, + round($this->iWidth*$this->iScale),round($this->iHeight*$this->iScale), + $this->iWidth,$this->iHeight); + } +} + + +//=================================================== +// CLASS TextProperty +// Description: Holds properties for a text +//=================================================== +class TextProperty { + public $iShow=true; + public $csimtarget='',$csimwintarget='',$csimalt=''; + private $iFFamily=FF_FONT1,$iFStyle=FS_NORMAL,$iFSize=10; + private $iFontArray=array(); + private $iColor="black"; + private $iText=""; + private $iHAlign="left",$iVAlign="bottom"; + + //--------------- + // CONSTRUCTOR + function __construct($aTxt='') { + $this->iText = $aTxt; + } + + //--------------- + // PUBLIC METHODS + function Set($aTxt) { + $this->iText = $aTxt; + } + + function SetCSIMTarget($aTarget,$aAltText='',$aWinTarget='') { + if( is_string($aTarget) ) + $aTarget = array($aTarget); + $this->csimtarget=$aTarget; + + if( is_string($aWinTarget) ) + $aWinTarget = array($aWinTarget); + $this->csimwintarget=$aWinTarget; + + if( is_string($aAltText) ) + $aAltText = array($aAltText); + $this->csimalt=$aAltText; + + } + + function SetCSIMAlt($aAltText) { + if( is_string($aAltText) ) + $aAltText = array($aAltText); + $this->csimalt=$aAltText; + } + + // Set text color + function SetColor($aColor) { + $this->iColor = $aColor; + } + + function HasTabs() { + if( is_string($this->iText) ) { + return substr_count($this->iText,"\t") > 0; + } + elseif( is_array($this->iText) ) { + return false; + } + } + + // Get number of tabs in string + function GetNbrTabs() { + if( is_string($this->iText) ) { + return substr_count($this->iText,"\t") ; + } + else{ + return 0; + } + } + + // Set alignment + function Align($aHAlign,$aVAlign="bottom") { + $this->iHAlign=$aHAlign; + $this->iVAlign=$aVAlign; + } + + // Synonym + function SetAlign($aHAlign,$aVAlign="bottom") { + $this->iHAlign=$aHAlign; + $this->iVAlign=$aVAlign; + } + + // Specify font + function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) { + $this->iFFamily = $aFFamily; + $this->iFStyle = $aFStyle; + $this->iFSize = $aFSize; + } + + function SetColumnFonts($aFontArray) { + if( !is_array($aFontArray) || count($aFontArray[0]) != 3 ) { + JpGraphError::RaiseL(6033); + // 'Array of fonts must contain arrays with 3 elements, i.e. (Family, Style, Size)' + } + $this->iFontArray = $aFontArray; + } + + + function IsColumns() { + return is_array($this->iText) ; + } + + // Get width of text. If text contains several columns separated by + // tabs then return both the total width as well as an array with a + // width for each column. + function GetWidth($aImg,$aUseTabs=false,$aTabExtraMargin=1.1) { + $extra_margin=4; + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + if( is_string($this->iText) ) { + if( strlen($this->iText) == 0 ) return 0; + $tmp = preg_split('/\t/',$this->iText); + if( count($tmp) <= 1 || !$aUseTabs ) { + $w = $aImg->GetTextWidth($this->iText); + return $w + 2*$extra_margin; + } + else { + $tot=0; + $n = count($tmp); + for($i=0; $i < $n; ++$i) { + $res[$i] = $aImg->GetTextWidth($tmp[$i]); + $tot += $res[$i]*$aTabExtraMargin; + } + return array(round($tot),$res); + } + } + elseif( is_object($this->iText) ) { + // A single icon + return $this->iText->GetWidth()+2*$extra_margin; + } + elseif( is_array($this->iText) ) { + // Must be an array of texts. In this case we return the sum of the + // length + a fixed margin of 4 pixels on each text string + $n = count($this->iText); + $nf = count($this->iFontArray); + for( $i=0, $w=0; $i < $n; ++$i ) { + if( $i < $nf ) { + $aImg->SetFont($this->iFontArray[$i][0],$this->iFontArray[$i][1],$this->iFontArray[$i][2]); + } + else { + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + } + $tmp = $this->iText[$i]; + if( is_string($tmp) ) { + $w += $aImg->GetTextWidth($tmp)+$extra_margin; + } + else { + if( is_object($tmp) === false ) { + JpGraphError::RaiseL(6012); + } + $w += $tmp->GetWidth()+$extra_margin; + } + } + return $w; + } + else { + JpGraphError::RaiseL(6012); + } + } + + // for the case where we have multiple columns this function returns the width of each + // column individually. If there is no columns just return the width of the single + // column as an array of one + function GetColWidth($aImg,$aMargin=0) { + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + if( is_array($this->iText) ) { + $n = count($this->iText); + $nf = count($this->iFontArray); + for( $i=0, $w=array(); $i < $n; ++$i ) { + $tmp = $this->iText[$i]; + if( is_string($tmp) ) { + if( $i < $nf ) { + $aImg->SetFont($this->iFontArray[$i][0],$this->iFontArray[$i][1],$this->iFontArray[$i][2]); + } + else { + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + } + $w[$i] = $aImg->GetTextWidth($tmp)+$aMargin; + } + else { + if( is_object($tmp) === false ) { + JpGraphError::RaiseL(6012); + } + $w[$i] = $tmp->GetWidth()+$aMargin; + } + } + return $w; + } + else { + return array($this->GetWidth($aImg)); + } + } + + // Get total height of text + function GetHeight($aImg) { + $nf = count($this->iFontArray); + $maxheight = -1; + + if( $nf > 0 ) { + // We have to find out the largest font and take that one as the + // height of the row + for($i=0; $i < $nf; ++$i ) { + $aImg->SetFont($this->iFontArray[$i][0],$this->iFontArray[$i][1],$this->iFontArray[$i][2]); + $height = $aImg->GetFontHeight(); + $maxheight = max($height,$maxheight); + } + } + + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + $height = $aImg->GetFontHeight(); + $maxheight = max($height,$maxheight); + return $maxheight; + } + + // Unhide/hide the text + function Show($aShow=true) { + $this->iShow=$aShow; + } + + // Stroke text at (x,y) coordinates. If the text contains tabs then the + // x parameter should be an array of positions to be used for each successive + // tab mark. If no array is supplied then the tabs will be ignored. + function Stroke($aImg,$aX,$aY) { + if( $this->iShow ) { + $aImg->SetColor($this->iColor); + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + $aImg->SetTextAlign($this->iHAlign,$this->iVAlign); + if( $this->GetNbrTabs() < 1 ) { + if( is_string($this->iText) ) { + if( is_array($aX) ) $aX=$aX[0]; + if( is_array($aY) ) $aY=$aY[0]; + $aImg->StrokeText($aX,$aY,$this->iText); + } + elseif( is_array($this->iText) && ($n = count($this->iText)) > 0 ) { + $ax = is_array($aX) ; + $ay = is_array($aY) ; + if( $ax && $ay ) { + // Nothing; both are already arrays + } + elseif( $ax ) { + $aY = array_fill(0,$n,$aY); + } + elseif( $ay ) { + $aX = array_fill(0,$n,$aX); + } + else { + $aX = array_fill(0,$n,$aX); + $aY = array_fill(0,$n,$aY); + } + $n = min($n, count($aX) ) ; + $n = min($n, count($aY) ) ; + for($i=0; $i < $n; ++$i ) { + $tmp = $this->iText[$i]; + if( is_object($tmp) ) { + $tmp->Stroke($aImg,$aX[$i],$aY[$i]); + } + else { + if( $i < count($this->iFontArray) ) { + $font = $this->iFontArray[$i]; + $aImg->SetFont($font[0],$font[1],$font[2]); + } + else { + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + } + $aImg->StrokeText($aX[$i],$aY[$i],str_replace("\t"," ",$tmp)); + } + } + } + } + else { + $tmp = preg_split('/\t/',$this->iText); + $n = min(count($tmp),count($aX)); + for($i=0; $i < $n; ++$i) { + if( $i < count($this->iFontArray) ) { + $font = $this->iFontArray[$i]; + $aImg->SetFont($font[0],$font[1],$font[2]); + } + else { + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + } + $aImg->StrokeText($aX[$i],$aY,$tmp[$i]); + } + } + } + } +} + +//=================================================== +// CLASS HeaderProperty +// Description: Data encapsulating class to hold property +// for each type of the scale headers +//=================================================== +class HeaderProperty { + public $grid; + public $iShowLabels=true,$iShowGrid=true; + public $iTitleVertMargin=3,$iFFamily=FF_FONT0,$iFStyle=FS_NORMAL,$iFSize=8; + public $iStyle=0; + public $iFrameColor="black",$iFrameWeight=1; + public $iBackgroundColor="white"; + public $iWeekendBackgroundColor="lightgray",$iSundayTextColor="red"; // these are only used with day scale + public $iTextColor="black"; + public $iLabelFormStr="%d"; + public $iIntervall = 1; + + //--------------- + // CONSTRUCTOR + function __construct() { + $this->grid = new LineProperty(); + } + + //--------------- + // PUBLIC METHODS + function Show($aShow=true) { + $this->iShowLabels = $aShow; + } + + function SetIntervall($aInt) { + $this->iIntervall = $aInt; + } + + function SetInterval($aInt) { + $this->iIntervall = $aInt; + } + + function GetIntervall() { + return $this->iIntervall ; + } + + function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) { + $this->iFFamily = $aFFamily; + $this->iFStyle = $aFStyle; + $this->iFSize = $aFSize; + } + + function SetFontColor($aColor) { + $this->iTextColor = $aColor; + } + + function GetFontHeight($aImg) { + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + return $aImg->GetFontHeight(); + } + + function GetFontWidth($aImg) { + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + return $aImg->GetFontWidth(); + } + + function GetStrWidth($aImg,$aStr) { + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + return $aImg->GetTextWidth($aStr); + } + + function SetStyle($aStyle) { + $this->iStyle = $aStyle; + } + + function SetBackgroundColor($aColor) { + $this->iBackgroundColor=$aColor; + } + + function SetFrameWeight($aWeight) { + $this->iFrameWeight=$aWeight; + } + + function SetFrameColor($aColor) { + $this->iFrameColor=$aColor; + } + + // Only used by day scale + function SetWeekendColor($aColor) { + $this->iWeekendBackgroundColor=$aColor; + } + + // Only used by day scale + function SetSundayFontColor($aColor) { + $this->iSundayTextColor=$aColor; + } + + function SetTitleVertMargin($aMargin) { + $this->iTitleVertMargin=$aMargin; + } + + function SetLabelFormatString($aStr) { + $this->iLabelFormStr=$aStr; + } + + function SetFormatString($aStr) { + $this->SetLabelFormatString($aStr); + } + + +} + +//=================================================== +// CLASS GanttScale +// Description: Responsible for calculating and showing +// the scale in a gantt chart. This includes providing methods for +// converting dates to position in the chart as well as stroking the +// date headers (days, week, etc). +//=================================================== +class GanttScale { + public $minute,$hour,$day,$week,$month,$year; + public $divider,$dividerh,$tableTitle; + public $iStartDate=-1,$iEndDate=-1; + // Number of gantt bar position (n.b not necessariliy the same as the number of bars) + // we could have on bar in position 1, and one bar in position 5 then there are two + // bars but the number of bar positions is 5 + public $actinfo; + public $iTopPlotMargin=10,$iBottomPlotMargin=15; + public $iVertLines=-1; + public $iVertHeaderSize=-1; + // The width of the labels (defaults to the widest of all labels) + private $iLabelWidth; + // Out image to stroke the scale to + private $iImg; + private $iTableHeaderBackgroundColor="white",$iTableHeaderFrameColor="black"; + private $iTableHeaderFrameWeight=1; + private $iAvailableHeight=-1,$iVertSpacing=-1; + private $iDateLocale; + private $iVertLayout=GANTT_EVEN; + private $iUsePlotWeekendBackground=true; + private $iWeekStart = 1; // Default to have weekends start on Monday + + //--------------- + // CONSTRUCTOR + function __construct($aImg) { + $this->iImg = $aImg; + $this->iDateLocale = new DateLocale(); + + $this->minute = new HeaderProperty(); + $this->minute->SetIntervall(15); + $this->minute->SetLabelFormatString('i'); + $this->minute->SetFont(FF_FONT0); + $this->minute->grid->SetColor("gray"); + + $this->hour = new HeaderProperty(); + $this->hour->SetFont(FF_FONT0); + $this->hour->SetIntervall(6); + $this->hour->SetStyle(HOURSTYLE_HM24); + $this->hour->SetLabelFormatString('H:i'); + $this->hour->grid->SetColor("gray"); + + $this->day = new HeaderProperty(); + $this->day->grid->SetColor("gray"); + $this->day->SetLabelFormatString('l'); + + $this->week = new HeaderProperty(); + $this->week->SetLabelFormatString("w%d"); + $this->week->SetFont(FF_FONT1); + + $this->month = new HeaderProperty(); + $this->month->SetFont(FF_FONT1,FS_BOLD); + + $this->year = new HeaderProperty(); + $this->year->SetFont(FF_FONT1,FS_BOLD); + + $this->divider=new LineProperty(); + $this->dividerh=new LineProperty(); + $this->dividerh->SetWeight(2); + $this->divider->SetWeight(6); + $this->divider->SetColor('gray'); + $this->divider->SetStyle('fancy'); + + $this->tableTitle=new TextProperty(); + $this->tableTitle->Show(false); + $this->actinfo = new GanttActivityInfo(); + } + + //--------------- + // PUBLIC METHODS + // Specify what headers should be visible + function ShowHeaders($aFlg) { + $this->day->Show($aFlg & GANTT_HDAY); + $this->week->Show($aFlg & GANTT_HWEEK); + $this->month->Show($aFlg & GANTT_HMONTH); + $this->year->Show($aFlg & GANTT_HYEAR); + $this->hour->Show($aFlg & GANTT_HHOUR); + $this->minute->Show($aFlg & GANTT_HMIN); + + // Make some default settings of gridlines whihc makes sense + if( $aFlg & GANTT_HWEEK ) { + $this->month->grid->Show(false); + $this->year->grid->Show(false); + } + if( $aFlg & GANTT_HHOUR ) { + $this->day->grid->SetColor("black"); + } + } + + // Should the weekend background stretch all the way down in the plotarea + function UseWeekendBackground($aShow) { + $this->iUsePlotWeekendBackground = $aShow; + } + + // Have a range been specified? + function IsRangeSet() { + return $this->iStartDate!=-1 && $this->iEndDate!=-1; + } + + // Should the layout be from top or even? + function SetVertLayout($aLayout) { + $this->iVertLayout = $aLayout; + } + + // Which locale should be used? + function SetDateLocale($aLocale) { + $this->iDateLocale->Set($aLocale); + } + + // Number of days we are showing + function GetNumberOfDays() { + return round(($this->iEndDate-$this->iStartDate)/SECPERDAY); + } + + // The width of the actual plot area + function GetPlotWidth() { + $img=$this->iImg; + return $img->width - $img->left_margin - $img->right_margin; + } + + // Specify the width of the titles(labels) for the activities + // (This is by default set to the minimum width enought for the + // widest title) + function SetLabelWidth($aLabelWidth) { + $this->iLabelWidth=$aLabelWidth; + } + + // Which day should the week start? + // 0==Sun, 1==Monday, 2==Tuesday etc + function SetWeekStart($aStartDay) { + $this->iWeekStart = $aStartDay % 7; + + //Recalculate the startday since this will change the week start + $this->SetRange($this->iStartDate,$this->iEndDate); + } + + // Do we show min scale? + function IsDisplayMinute() { + return $this->minute->iShowLabels; + } + + // Do we show day scale? + function IsDisplayHour() { + return $this->hour->iShowLabels; + } + + + // Do we show day scale? + function IsDisplayDay() { + return $this->day->iShowLabels; + } + + // Do we show week scale? + function IsDisplayWeek() { + return $this->week->iShowLabels; + } + + // Do we show month scale? + function IsDisplayMonth() { + return $this->month->iShowLabels; + } + + // Do we show year scale? + function IsDisplayYear() { + return $this->year->iShowLabels; + } + + // Specify spacing (in percent of bar height) between activity bars + function SetVertSpacing($aSpacing) { + $this->iVertSpacing = $aSpacing; + } + + // Specify scale min and max date either as timestamp or as date strings + // Always round to the nearest week boundary + function SetRange($aMin,$aMax) { + $this->iStartDate = $this->NormalizeDate($aMin); + $this->iEndDate = $this->NormalizeDate($aMax); + } + + + // Adjust the start and end date so they fit to beginning/ending + // of the week taking the specified week start day into account. + function AdjustStartEndDay() { + + if( !($this->IsDisplayYear() ||$this->IsDisplayMonth() || $this->IsDisplayWeek()) ) { + // Don't adjust + return; + } + + // Get day in week for start and ending date (Sun==0) + $ds=strftime("%w",$this->iStartDate); + $de=strftime("%w",$this->iEndDate); + + // We want to start on iWeekStart day. But first we subtract a week + // if the startdate is "behind" the day the week start at. + // This way we ensure that the given start date is always included + // in the range. If we don't do this the nearest correct weekday in the week + // to start at might be later than the start date. + if( $ds < $this->iWeekStart ) + $d = strtotime('-7 day',$this->iStartDate); + else + $d = $this->iStartDate; + $adjdate = strtotime(($this->iWeekStart-$ds).' day',$d /*$this->iStartDate*/ ); + $this->iStartDate = $adjdate; + + // We want to end on the last day of the week + $preferredEndDay = ($this->iWeekStart+6)%7; + if( $preferredEndDay != $de ) { + // Solve equivalence eq: $de + x ~ $preferredDay (mod 7) + $adj = (7+($preferredEndDay - $de)) % 7; + $adjdate = strtotime("+$adj day",$this->iEndDate); + $this->iEndDate = $adjdate; + } + } + + // Specify background for the table title area (upper left corner of the table) + function SetTableTitleBackground($aColor) { + $this->iTableHeaderBackgroundColor = $aColor; + } + + /////////////////////////////////////// + // PRIVATE Methods + + // Determine the height of all the scale headers combined + function GetHeaderHeight() { + $img=$this->iImg; + $height=1; + if( $this->minute->iShowLabels ) { + $height += $this->minute->GetFontHeight($img); + $height += $this->minute->iTitleVertMargin; + } + if( $this->hour->iShowLabels ) { + $height += $this->hour->GetFontHeight($img); + $height += $this->hour->iTitleVertMargin; + } + if( $this->day->iShowLabels ) { + $height += $this->day->GetFontHeight($img); + $height += $this->day->iTitleVertMargin; + } + if( $this->week->iShowLabels ) { + $height += $this->week->GetFontHeight($img); + $height += $this->week->iTitleVertMargin; + } + if( $this->month->iShowLabels ) { + $height += $this->month->GetFontHeight($img); + $height += $this->month->iTitleVertMargin; + } + if( $this->year->iShowLabels ) { + $height += $this->year->GetFontHeight($img); + $height += $this->year->iTitleVertMargin; + } + return $height; + } + + // Get width (in pixels) for a single day + function GetDayWidth() { + return ($this->GetPlotWidth()-$this->iLabelWidth+1)/$this->GetNumberOfDays(); + } + + // Get width (in pixels) for a single hour + function GetHourWidth() { + return $this->GetDayWidth() / 24 ; + } + + function GetMinuteWidth() { + return $this->GetHourWidth() / 60 ; + } + + // Nuber of days in a year + function GetNumDaysInYear($aYear) { + if( $this->IsLeap($aYear) ) + return 366; + else + return 365; + } + + // Get week number + function GetWeekNbr($aDate,$aSunStart=true) { + // We can't use the internal strftime() since it gets the weeknumber + // wrong since it doesn't follow ISO on all systems since this is + // system linrary dependent. + // Even worse is that this works differently if we are on a Windows + // or UNIX box (it even differs between UNIX boxes how strftime() + // is natively implemented) + // + // Credit to Nicolas Hoizey for this elegant + // version of Week Nbr calculation. + + $day = $this->NormalizeDate($aDate); + if( $aSunStart ) + $day += 60*60*24; + + /*------------------------------------------------------------------------- + According to ISO-8601 : + "Week 01 of a year is per definition the first week that has the Thursday in this year, + which is equivalent to the week that contains the fourth day of January. + In other words, the first week of a new year is the week that has the majority of its + days in the new year." + + Be carefull, with PHP, -3 % 7 = -3, instead of 4 !!! + + day of year = date("z", $day) + 1 + offset to thursday = 3 - (date("w", $day) + 6) % 7 + first thursday of year = 1 + (11 - date("w", mktime(0, 0, 0, 1, 1, date("Y", $day)))) % 7 + week number = (thursday's day of year - first thursday's day of year) / 7 + 1 + ---------------------------------------------------------------------------*/ + + $thursday = $day + 60 * 60 * 24 * (3 - (date("w", $day) + 6) % 7); // take week's thursday + $week = 1 + (date("z", $thursday) - (11 - date("w", mktime(0, 0, 0, 1, 1, date("Y", $thursday)))) % 7) / 7; + + return $week; + } + + // Is year a leap year? + function IsLeap($aYear) { + // Is the year a leap year? + //$year = 0+date("Y",$aDate); + if( $aYear % 4 == 0) + if( !($aYear % 100 == 0) || ($aYear % 400 == 0) ) + return true; + return false; + } + + // Get current year + function GetYear($aDate) { + return 0+Date("Y",$aDate); + } + + // Return number of days in a year + function GetNumDaysInMonth($aMonth,$aYear) { + $days=array(31,28,31,30,31,30,31,31,30,31,30,31); + $daysl=array(31,29,31,30,31,30,31,31,30,31,30,31); + if( $this->IsLeap($aYear)) + return $daysl[$aMonth]; + else + return $days[$aMonth]; + } + + // Get day in month + function GetMonthDayNbr($aDate) { + return 0+strftime("%d",$aDate); + } + + // Get day in year + function GetYearDayNbr($aDate) { + return 0+strftime("%j",$aDate); + } + + // Get month number + function GetMonthNbr($aDate) { + return 0+strftime("%m",$aDate); + } + + // Translate a date to screen coordinates (horizontal scale) + function TranslateDate($aDate) { + // + // In order to handle the problem with Daylight savings time + // the scale written with equal number of seconds per day beginning + // with the start date. This means that we "cement" the state of + // DST as it is in the start date. If later the scale includes the + // switchover date (depends on the locale) we need to adjust back + // if the date we try to translate has a different DST status since + // we would otherwise be off by one hour. + $aDate = $this->NormalizeDate($aDate); + $tmp = localtime($aDate); + $cloc = $tmp[8]; + $tmp = localtime($this->iStartDate); + $sloc = $tmp[8]; + $offset = 0; + if( $sloc != $cloc) { + if( $sloc ) + $offset = 3600; + else + $offset = -3600; + } + $img=$this->iImg; + return ($aDate-$this->iStartDate-$offset)/SECPERDAY*$this->GetDayWidth()+$img->left_margin+$this->iLabelWidth;; + } + + // Get screen coordinatesz for the vertical position for a bar + function TranslateVertPos($aPos,$atTop=false) { + $img=$this->iImg; + if( $aPos > $this->iVertLines ) + JpGraphError::RaiseL(6015,$aPos); + // 'Illegal vertical position %d' + if( $this->iVertLayout == GANTT_EVEN ) { + // Position the top bar at 1 vert spacing from the scale + $pos = round($img->top_margin + $this->iVertHeaderSize + ($aPos+1)*$this->iVertSpacing); + } + else { + // position the top bar at 1/2 a vert spacing from the scale + $pos = round($img->top_margin + $this->iVertHeaderSize + $this->iTopPlotMargin + ($aPos+1)*$this->iVertSpacing); + } + + if( $atTop ) + $pos -= $this->iVertSpacing; + + return $pos; + } + + // What is the vertical spacing? + function GetVertSpacing() { + return $this->iVertSpacing; + } + + // Convert a date to timestamp + function NormalizeDate($aDate) { + if( $aDate === false ) return false; + if( is_string($aDate) ) { + $t = strtotime($aDate); + if( $t === FALSE || $t === -1 ) { + JpGraphError::RaiseL(6016,$aDate); + //("Date string ($aDate) specified for Gantt activity can not be interpretated. Please make sure it is a valid time string, e.g. 2005-04-23 13:30"); + } + return $t; + } + elseif( is_int($aDate) || is_float($aDate) ) + return $aDate; + else + JpGraphError::RaiseL(6017,$aDate); + //Unknown date format in GanttScale ($aDate)."); + } + + + // Convert a time string to minutes + + function TimeToMinutes($aTimeString) { + // Split in hours and minutes + $pos=strpos($aTimeString,':'); + $minint=60; + if( $pos === false ) { + $hourint = $aTimeString; + $minint = 0; + } + else { + $hourint = floor(substr($aTimeString,0,$pos)); + $minint = floor(substr($aTimeString,$pos+1)); + } + $minint += 60 * $hourint; + return $minint; + } + + // Stroke the day scale (including gridlines) + function StrokeMinutes($aYCoord,$getHeight=false) { + $img=$this->iImg; + $xt=$img->left_margin+$this->iLabelWidth; + $yt=$aYCoord+$img->top_margin; + if( $this->minute->iShowLabels ) { + $img->SetFont($this->minute->iFFamily,$this->minute->iFStyle,$this->minute->iFSize); + $yb = $yt + $img->GetFontHeight() + + $this->minute->iTitleVertMargin + $this->minute->iFrameWeight; + if( $getHeight ) { + return $yb - $img->top_margin; + } + $xb = $img->width-$img->right_margin+1; + $img->SetColor($this->minute->iBackgroundColor); + $img->FilledRectangle($xt,$yt,$xb,$yb); + + $x = $xt; + $img->SetTextAlign("center"); + $day = date('w',$this->iStartDate); + $minint = $this->minute->GetIntervall() ; + + if( 60 % $minint !== 0 ) { + JpGraphError::RaiseL(6018,$minint); + //'Intervall for minutes must divide the hour evenly, e.g. 1,5,10,12,15,20,30 etc You have specified an intervall of '.$minint.' minutes.'); + } + + + $n = 60 / $minint; + $datestamp = $this->iStartDate; + $width = $this->GetHourWidth() / $n ; + if( $width < 8 ) { + // TO small width to draw minute scale + JpGraphError::RaiseL(6019,$width); + //('The available width ('.$width.') for minutes are to small for this scale to be displayed. Please use auto-sizing or increase the width of the graph.'); + } + + $nh = ceil(24*60 / $this->TimeToMinutes($this->hour->GetIntervall()) ); + $nd = $this->GetNumberOfDays(); + // Convert to intervall to seconds + $minint *= 60; + for($j=0; $j < $nd; ++$j, $day += 1, $day %= 7) { + for( $k=0; $k < $nh; ++$k ) { + for($i=0; $i < $n ;++$i, $x+=$width, $datestamp += $minint ) { + if( $day==6 || $day==0 ) { + + $img->PushColor($this->day->iWeekendBackgroundColor); + if( $this->iUsePlotWeekendBackground ) + $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$img->height-$img->bottom_margin); + else + $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$yb-$this->day->iFrameWeight); + $img->PopColor(); + + } + + if( $day==0 ) + $img->SetColor($this->day->iSundayTextColor); + else + $img->SetColor($this->day->iTextColor); + + switch( $this->minute->iStyle ) { + case MINUTESTYLE_CUSTOM: + $txt = date($this->minute->iLabelFormStr,$datestamp); + break; + case MINUTESTYLE_MM: + default: + // 15 + $txt = date('i',$datestamp); + break; + } + $img->StrokeText(round($x+$width/2),round($yb-$this->minute->iTitleVertMargin),$txt); + + // Fix a rounding problem the wrong way .. + // If we also have hour scale then don't draw the firsta or last + // gridline since that will be overwritten by the hour scale gridline if such exists. + // However, due to the propagation of rounding of the 'x+=width' term in the loop + // this might sometimes be one pixel of so we fix this by not drawing it. + // The proper way to fix it would be to re-calculate the scale for each step and + // not using the additive term. + if( !(($i == $n || $i==0) && $this->hour->iShowLabels && $this->hour->grid->iShow) ) { + $img->SetColor($this->minute->grid->iColor); + $img->SetLineWeight($this->minute->grid->iWeight); + $img->Line($x,$yt,$x,$yb); + $this->minute->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); + } + } + } + } + $img->SetColor($this->minute->iFrameColor); + $img->SetLineWeight($this->minute->iFrameWeight); + $img->Rectangle($xt,$yt,$xb,$yb); + return $yb - $img->top_margin; + } + return $aYCoord; + } + + // Stroke the day scale (including gridlines) + function StrokeHours($aYCoord,$getHeight=false) { + $img=$this->iImg; + $xt=$img->left_margin+$this->iLabelWidth; + $yt=$aYCoord+$img->top_margin; + if( $this->hour->iShowLabels ) { + $img->SetFont($this->hour->iFFamily,$this->hour->iFStyle,$this->hour->iFSize); + $yb = $yt + $img->GetFontHeight() + + $this->hour->iTitleVertMargin + $this->hour->iFrameWeight; + if( $getHeight ) { + return $yb - $img->top_margin; + } + $xb = $img->width-$img->right_margin+1; + $img->SetColor($this->hour->iBackgroundColor); + $img->FilledRectangle($xt,$yt,$xb,$yb); + + $x = $xt; + $img->SetTextAlign("center"); + $tmp = $this->hour->GetIntervall() ; + $minint = $this->TimeToMinutes($tmp); + if( 1440 % $minint !== 0 ) { + JpGraphError::RaiseL(6020,$tmp); + //('Intervall for hours must divide the day evenly, e.g. 0:30, 1:00, 1:30, 4:00 etc. You have specified an intervall of '.$tmp); + } + + $n = ceil(24*60 / $minint ); + $datestamp = $this->iStartDate; + $day = date('w',$this->iStartDate); + $doback = !$this->minute->iShowLabels; + $width = $this->GetDayWidth() / $n ; + for($j=0; $j < $this->GetNumberOfDays(); ++$j, $day += 1,$day %= 7) { + for($i=0; $i < $n ;++$i, $x+=$width) { + if( $day==6 || $day==0 ) { + + $img->PushColor($this->day->iWeekendBackgroundColor); + if( $this->iUsePlotWeekendBackground && $doback ) + $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$img->height-$img->bottom_margin); + else + $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$yb-$this->day->iFrameWeight); + $img->PopColor(); + + } + + if( $day==0 ) + $img->SetColor($this->day->iSundayTextColor); + else + $img->SetColor($this->day->iTextColor); + + switch( $this->hour->iStyle ) { + case HOURSTYLE_HMAMPM: + // 1:35pm + $txt = date('g:ia',$datestamp); + break; + case HOURSTYLE_H24: + // 13 + $txt = date('H',$datestamp); + break; + case HOURSTYLE_HAMPM: + $txt = date('ga',$datestamp); + break; + case HOURSTYLE_CUSTOM: + $txt = date($this->hour->iLabelFormStr,$datestamp); + break; + case HOURSTYLE_HM24: + default: + $txt = date('H:i',$datestamp); + break; + } + $img->StrokeText(round($x+$width/2),round($yb-$this->hour->iTitleVertMargin),$txt); + $img->SetColor($this->hour->grid->iColor); + $img->SetLineWeight($this->hour->grid->iWeight); + $img->Line($x,$yt,$x,$yb); + $this->hour->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); + //$datestamp += $minint*60 + $datestamp = mktime(date('H',$datestamp),date('i',$datestamp)+$minint,0, + date("m",$datestamp),date("d",$datestamp)+1,date("Y",$datestamp)); + + } + } + $img->SetColor($this->hour->iFrameColor); + $img->SetLineWeight($this->hour->iFrameWeight); + $img->Rectangle($xt,$yt,$xb,$yb); + return $yb - $img->top_margin; + } + return $aYCoord; + } + + + // Stroke the day scale (including gridlines) + function StrokeDays($aYCoord,$getHeight=false) { + $img=$this->iImg; + $daywidth=$this->GetDayWidth(); + $xt=$img->left_margin+$this->iLabelWidth; + $yt=$aYCoord+$img->top_margin; + if( $this->day->iShowLabels ) { + $img->SetFont($this->day->iFFamily,$this->day->iFStyle,$this->day->iFSize); + $yb=$yt + $img->GetFontHeight() + $this->day->iTitleVertMargin + $this->day->iFrameWeight; + if( $getHeight ) { + return $yb - $img->top_margin; + } + $xb=$img->width-$img->right_margin+1; + $img->SetColor($this->day->iBackgroundColor); + $img->FilledRectangle($xt,$yt,$xb,$yb); + + $x = $xt; + $img->SetTextAlign("center"); + $day = date('w',$this->iStartDate); + $datestamp = $this->iStartDate; + + $doback = !($this->hour->iShowLabels || $this->minute->iShowLabels); + + setlocale(LC_TIME,$this->iDateLocale->iLocale); + + for($i=0; $i < $this->GetNumberOfDays(); ++$i, $x+=$daywidth, $day += 1,$day %= 7) { + if( $day==6 || $day==0 ) { + $img->SetColor($this->day->iWeekendBackgroundColor); + if( $this->iUsePlotWeekendBackground && $doback) + $img->FilledRectangle($x,$yt+$this->day->iFrameWeight, + $x+$daywidth,$img->height-$img->bottom_margin); + else + $img->FilledRectangle($x,$yt+$this->day->iFrameWeight, + $x+$daywidth,$yb-$this->day->iFrameWeight); + } + + $mn = strftime('%m',$datestamp); + if( $mn[0]=='0' ) + $mn = $mn[1]; + + switch( $this->day->iStyle ) { + case DAYSTYLE_LONG: + // "Monday" + $txt = strftime('%A',$datestamp); + break; + case DAYSTYLE_SHORT: + // "Mon" + $txt = strftime('%a',$datestamp); + break; + case DAYSTYLE_SHORTDAYDATE1: + // "Mon 23/6" + $txt = strftime('%a %d/'.$mn,$datestamp); + break; + case DAYSTYLE_SHORTDAYDATE2: + // "Mon 23 Jun" + $txt = strftime('%a %d %b',$datestamp); + break; + case DAYSTYLE_SHORTDAYDATE3: + // "Mon 23 Jun 2003" + $txt = strftime('%a %d %b %Y',$datestamp); + break; + case DAYSTYLE_LONGDAYDATE1: + // "Monday 23 Jun" + $txt = strftime('%A %d %b',$datestamp); + break; + case DAYSTYLE_LONGDAYDATE2: + // "Monday 23 Jun 2003" + $txt = strftime('%A %d %b %Y',$datestamp); + break; + case DAYSTYLE_SHORTDATE1: + // "23/6" + $txt = strftime('%d/'.$mn,$datestamp); + break; + case DAYSTYLE_SHORTDATE2: + // "23 Jun" + $txt = strftime('%d %b',$datestamp); + break; + case DAYSTYLE_SHORTDATE3: + // "Mon 23" + $txt = strftime('%a %d',$datestamp); + break; + case DAYSTYLE_SHORTDATE4: + // "23" + $txt = strftime('%d',$datestamp); + break; + case DAYSTYLE_CUSTOM: + // Custom format + $txt = strftime($this->day->iLabelFormStr,$datestamp); + break; + case DAYSTYLE_ONELETTER: + default: + // "M" + $txt = strftime('%A',$datestamp); + $txt = strtoupper($txt[0]); + break; + } + + if( $day==0 ) + $img->SetColor($this->day->iSundayTextColor); + else + $img->SetColor($this->day->iTextColor); + $img->StrokeText(round($x+$daywidth/2+1), + round($yb-$this->day->iTitleVertMargin),$txt); + $img->SetColor($this->day->grid->iColor); + $img->SetLineWeight($this->day->grid->iWeight); + $img->Line($x,$yt,$x,$yb); + $this->day->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); + $datestamp = mktime(0,0,0,date("m",$datestamp),date("d",$datestamp)+1,date("Y",$datestamp)); + //$datestamp += SECPERDAY; + + } + $img->SetColor($this->day->iFrameColor); + $img->SetLineWeight($this->day->iFrameWeight); + $img->Rectangle($xt,$yt,$xb,$yb); + return $yb - $img->top_margin; + } + return $aYCoord; + } + + // Stroke week header and grid + function StrokeWeeks($aYCoord,$getHeight=false) { + if( $this->week->iShowLabels ) { + $img=$this->iImg; + $yt=$aYCoord+$img->top_margin; + $img->SetFont($this->week->iFFamily,$this->week->iFStyle,$this->week->iFSize); + $yb=$yt + $img->GetFontHeight() + $this->week->iTitleVertMargin + $this->week->iFrameWeight; + + if( $getHeight ) { + return $yb - $img->top_margin; + } + + $xt=$img->left_margin+$this->iLabelWidth; + $weekwidth=$this->GetDayWidth()*7; + $wdays=$this->iDateLocale->GetDayAbb(); + $xb=$img->width-$img->right_margin+1; + $week = $this->iStartDate; + $weeknbr=$this->GetWeekNbr($week); + $img->SetColor($this->week->iBackgroundColor); + $img->FilledRectangle($xt,$yt,$xb,$yb); + $img->SetColor($this->week->grid->iColor); + $x = $xt; + if( $this->week->iStyle==WEEKSTYLE_WNBR ) { + $img->SetTextAlign("center"); + $txtOffset = $weekwidth/2+1; + } + elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY || + $this->week->iStyle==WEEKSTYLE_FIRSTDAY2 || + $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR || + $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) { + $img->SetTextAlign("left"); + $txtOffset = 3; + } + else { + JpGraphError::RaiseL(6021); + //("Unknown formatting style for week."); + } + + for($i=0; $i<$this->GetNumberOfDays()/7; ++$i, $x+=$weekwidth) { + $img->PushColor($this->week->iTextColor); + + if( $this->week->iStyle==WEEKSTYLE_WNBR ) + $txt = sprintf($this->week->iLabelFormStr,$weeknbr); + elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY || + $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ) + $txt = date("j/n",$week); + elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY2 || + $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) { + $monthnbr = date("n",$week)-1; + $shortmonth = $this->iDateLocale->GetShortMonthName($monthnbr); + $txt = Date("j",$week)." ".$shortmonth; + } + + if( $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR || + $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) { + $w = sprintf($this->week->iLabelFormStr,$weeknbr); + $txt .= ' '.$w; + } + + $img->StrokeText(round($x+$txtOffset), + round($yb-$this->week->iTitleVertMargin),$txt); + + $week = strtotime('+7 day',$week); + $weeknbr = $this->GetWeekNbr($week); + $img->PopColor(); + $img->SetLineWeight($this->week->grid->iWeight); + $img->Line($x,$yt,$x,$yb); + $this->week->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); + } + $img->SetColor($this->week->iFrameColor); + $img->SetLineWeight($this->week->iFrameWeight); + $img->Rectangle($xt,$yt,$xb,$yb); + return $yb-$img->top_margin; + } + return $aYCoord; + } + + // Format the mont scale header string + function GetMonthLabel($aMonthNbr,$year) { + $sn = $this->iDateLocale->GetShortMonthName($aMonthNbr); + $ln = $this->iDateLocale->GetLongMonthName($aMonthNbr); + switch($this->month->iStyle) { + case MONTHSTYLE_SHORTNAME: + $m=$sn; + break; + case MONTHSTYLE_LONGNAME: + $m=$ln; + break; + case MONTHSTYLE_SHORTNAMEYEAR2: + $m=$sn." '".substr("".$year,2); + break; + case MONTHSTYLE_SHORTNAMEYEAR4: + $m=$sn." ".$year; + break; + case MONTHSTYLE_LONGNAMEYEAR2: + $m=$ln." '".substr("".$year,2); + break; + case MONTHSTYLE_LONGNAMEYEAR4: + $m=$ln." ".$year; + break; + case MONTHSTYLE_FIRSTLETTER: + $m=$sn[0]; + break; + } + return $m; + } + + // Stroke month scale and gridlines + function StrokeMonths($aYCoord,$getHeight=false) { + if( $this->month->iShowLabels ) { + $img=$this->iImg; + $img->SetFont($this->month->iFFamily,$this->month->iFStyle,$this->month->iFSize); + $yt=$aYCoord+$img->top_margin; + $yb=$yt + $img->GetFontHeight() + $this->month->iTitleVertMargin + $this->month->iFrameWeight; + if( $getHeight ) { + return $yb - $img->top_margin; + } + $monthnbr = $this->GetMonthNbr($this->iStartDate)-1; + $xt=$img->left_margin+$this->iLabelWidth; + $xb=$img->width-$img->right_margin+1; + + $img->SetColor($this->month->iBackgroundColor); + $img->FilledRectangle($xt,$yt,$xb,$yb); + + $img->SetLineWeight($this->month->grid->iWeight); + $img->SetColor($this->month->iTextColor); + $year = 0+strftime("%Y",$this->iStartDate); + $img->SetTextAlign("center"); + if( $this->GetMonthNbr($this->iStartDate) == $this->GetMonthNbr($this->iEndDate) + && $this->GetYear($this->iStartDate)==$this->GetYear($this->iEndDate) ) { + $monthwidth=$this->GetDayWidth()*($this->GetMonthDayNbr($this->iEndDate) - $this->GetMonthDayNbr($this->iStartDate) + 1); + } + else { + $monthwidth=$this->GetDayWidth()*($this->GetNumDaysInMonth($monthnbr,$year)-$this->GetMonthDayNbr($this->iStartDate)+1); + } + // Is it enough space to stroke the first month? + $monthName = $this->GetMonthLabel($monthnbr,$year); + if( $monthwidth >= 1.2*$img->GetTextWidth($monthName) ) { + $img->SetColor($this->month->iTextColor); + $img->StrokeText(round($xt+$monthwidth/2+1), + round($yb-$this->month->iTitleVertMargin), + $monthName); + } + $x = $xt + $monthwidth; + while( $x < $xb ) { + $img->SetColor($this->month->grid->iColor); + $img->Line($x,$yt,$x,$yb); + $this->month->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); + $monthnbr++; + if( $monthnbr==12 ) { + $monthnbr=0; + $year++; + } + $monthName = $this->GetMonthLabel($monthnbr,$year); + $monthwidth=$this->GetDayWidth()*$this->GetNumDaysInMonth($monthnbr,$year); + if( $x + $monthwidth < $xb ) + $w = $monthwidth; + else + $w = $xb-$x; + if( $w >= 1.2*$img->GetTextWidth($monthName) ) { + $img->SetColor($this->month->iTextColor); + $img->StrokeText(round($x+$w/2+1), + round($yb-$this->month->iTitleVertMargin),$monthName); + } + $x += $monthwidth; + } + $img->SetColor($this->month->iFrameColor); + $img->SetLineWeight($this->month->iFrameWeight); + $img->Rectangle($xt,$yt,$xb,$yb); + return $yb-$img->top_margin; + } + return $aYCoord; + } + + // Stroke year scale and gridlines + function StrokeYears($aYCoord,$getHeight=false) { + if( $this->year->iShowLabels ) { + $img=$this->iImg; + $yt=$aYCoord+$img->top_margin; + $img->SetFont($this->year->iFFamily,$this->year->iFStyle,$this->year->iFSize); + $yb=$yt + $img->GetFontHeight() + $this->year->iTitleVertMargin + $this->year->iFrameWeight; + + if( $getHeight ) { + return $yb - $img->top_margin; + } + + $xb=$img->width-$img->right_margin+1; + $xt=$img->left_margin+$this->iLabelWidth; + $year = $this->GetYear($this->iStartDate); + $img->SetColor($this->year->iBackgroundColor); + $img->FilledRectangle($xt,$yt,$xb,$yb); + $img->SetLineWeight($this->year->grid->iWeight); + $img->SetTextAlign("center"); + if( $year == $this->GetYear($this->iEndDate) ) + $yearwidth=$this->GetDayWidth()*($this->GetYearDayNbr($this->iEndDate)-$this->GetYearDayNbr($this->iStartDate)+1); + else + $yearwidth=$this->GetDayWidth()*($this->GetNumDaysInYear($year)-$this->GetYearDayNbr($this->iStartDate)+1); + + // The space for a year must be at least 20% bigger than the actual text + // so we allow 10% margin on each side + if( $yearwidth >= 1.20*$img->GetTextWidth("".$year) ) { + $img->SetColor($this->year->iTextColor); + $img->StrokeText(round($xt+$yearwidth/2+1), + round($yb-$this->year->iTitleVertMargin), + $year); + } + $x = $xt + $yearwidth; + while( $x < $xb ) { + $img->SetColor($this->year->grid->iColor); + $img->Line($x,$yt,$x,$yb); + $this->year->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); + $year += 1; + $yearwidth=$this->GetDayWidth()*$this->GetNumDaysInYear($year); + if( $x + $yearwidth < $xb ) + $w = $yearwidth; + else + $w = $xb-$x; + if( $w >= 1.2*$img->GetTextWidth("".$year) ) { + $img->SetColor($this->year->iTextColor); + $img->StrokeText(round($x+$w/2+1), + round($yb-$this->year->iTitleVertMargin), + $year); + } + $x += $yearwidth; + } + $img->SetColor($this->year->iFrameColor); + $img->SetLineWeight($this->year->iFrameWeight); + $img->Rectangle($xt,$yt,$xb,$yb); + return $yb-$img->top_margin; + } + return $aYCoord; + } + + // Stroke table title (upper left corner) + function StrokeTableHeaders($aYBottom) { + $img=$this->iImg; + $xt=$img->left_margin; + $yt=$img->top_margin; + $xb=$xt+$this->iLabelWidth; + $yb=$aYBottom+$img->top_margin; + + if( $this->tableTitle->iShow ) { + $img->SetColor($this->iTableHeaderBackgroundColor); + $img->FilledRectangle($xt,$yt,$xb,$yb); + $this->tableTitle->Align("center","top"); + $this->tableTitle->Stroke($img,$xt+($xb-$xt)/2+1,$yt+2); + $img->SetColor($this->iTableHeaderFrameColor); + $img->SetLineWeight($this->iTableHeaderFrameWeight); + $img->Rectangle($xt,$yt,$xb,$yb); + } + + $this->actinfo->Stroke($img,$xt,$yt,$xb,$yb,$this->tableTitle->iShow); + + + // Draw the horizontal dividing line + $this->dividerh->Stroke($img,$xt,$yb,$img->width-$img->right_margin,$yb); + + // Draw the vertical dividing line + // We do the width "manually" since we want the line only to grow + // to the left + $fancy = $this->divider->iStyle == 'fancy' ; + if( $fancy ) { + $this->divider->iStyle = 'solid'; + } + + $tmp = $this->divider->iWeight; + $this->divider->iWeight=1; + $y = $img->height-$img->bottom_margin; + for($i=0; $i < $tmp; ++$i ) { + $this->divider->Stroke($img,$xb-$i,$yt,$xb-$i,$y); + } + + // Should we draw "fancy" divider + if( $fancy ) { + $img->SetLineWeight(1); + $img->SetColor($this->iTableHeaderFrameColor); + $img->Line($xb,$yt,$xb,$y); + $img->Line($xb-$tmp+1,$yt,$xb-$tmp+1,$y); + $img->SetColor('white'); + $img->Line($xb-$tmp+2,$yt,$xb-$tmp+2,$y); + } + } + + // Main entry point to stroke scale + function Stroke() { + if( !$this->IsRangeSet() ) { + JpGraphError::RaiseL(6022); + //("Gantt scale has not been specified."); + } + $img=$this->iImg; + + // If minutes are displayed then hour interval must be 1 + if( $this->IsDisplayMinute() && $this->hour->GetIntervall() > 1 ) { + JpGraphError::RaiseL(6023); + //('If you display both hour and minutes the hour intervall must be 1 (Otherwise it doesn\' make sense to display minutes).'); + } + + // Stroke all headers. As argument we supply the offset from the + // top which depends on any previous headers + + // First find out the height of each header + $offy=$this->StrokeYears(0,true); + $offm=$this->StrokeMonths($offy,true); + $offw=$this->StrokeWeeks($offm,true); + $offd=$this->StrokeDays($offw,true); + $offh=$this->StrokeHours($offd,true); + $offmin=$this->StrokeMinutes($offh,true); + + + // ... then we can stroke them in the "backwards order to ensure that + // the larger scale gridlines is stroked over the smaller scale gridline + $this->StrokeMinutes($offh); + $this->StrokeHours($offd); + $this->StrokeDays($offw); + $this->StrokeWeeks($offm); + $this->StrokeMonths($offy); + $this->StrokeYears(0); + + // Now when we now the oaverall size of the scale headers + // we can stroke the overall table headers + $this->StrokeTableHeaders($offmin); + + // Now we can calculate the correct scaling factor for each vertical position + $this->iAvailableHeight = $img->height - $img->top_margin - $img->bottom_margin - $offd; + + $this->iVertHeaderSize = $offmin; + if( $this->iVertSpacing == -1 ) + $this->iVertSpacing = $this->iAvailableHeight / $this->iVertLines; + } +} + + +//=================================================== +// CLASS GanttConstraint +// Just a structure to store all the values for a constraint +//=================================================== +class GanttConstraint { + public $iConstrainRow; + public $iConstrainType; + public $iConstrainColor; + public $iConstrainArrowSize; + public $iConstrainArrowType; + + //--------------- + // CONSTRUCTOR + function __construct($aRow,$aType,$aColor,$aArrowSize,$aArrowType){ + $this->iConstrainType = $aType; + $this->iConstrainRow = $aRow; + $this->iConstrainColor=$aColor; + $this->iConstrainArrowSize=$aArrowSize; + $this->iConstrainArrowType=$aArrowType; + } +} + + +//=================================================== +// CLASS GanttPlotObject +// The common signature for a Gantt object +//=================================================== +class GanttPlotObject { + public $title,$caption; + public $csimarea='',$csimtarget='',$csimwintarget='',$csimalt=''; + public $constraints = array(); + public $iCaptionMargin=5; + public $iConstrainPos=array(); + protected $iStart=""; // Start date + public $iVPos=0; // Vertical position + protected $iLabelLeftMargin=2; // Title margin + + function __construct() { + $this->title = new TextProperty(); + $this->title->Align('left','center'); + $this->caption = new TextProperty(); + } + + function GetCSIMArea() { + return $this->csimarea; + } + + function SetCSIMTarget($aTarget,$aAlt='',$aWinTarget='') { + if( !is_string($aTarget) ) { + $tv = substr(var_export($aTarget,true),0,40); + JpGraphError::RaiseL(6024,$tv); + //('CSIM Target must be specified as a string.'."\nStart of target is:\n$tv"); + } + if( !is_string($aAlt) ) { + $tv = substr(var_export($aAlt,true),0,40); + JpGraphError::RaiseL(6025,$tv); + //('CSIM Alt text must be specified as a string.'."\nStart of alt text is:\n$tv"); + } + + $this->csimtarget=$aTarget; + $this->csimwintarget=$aWinTarget; + $this->csimalt=$aAlt; + } + + function SetCSIMAlt($aAlt) { + if( !is_string($aAlt) ) { + $tv = substr(var_export($aAlt,true),0,40); + JpGraphError::RaiseL(6025,$tv); + //('CSIM Alt text must be specified as a string.'."\nStart of alt text is:\n$tv"); + } + $this->csimalt=$aAlt; + } + + function SetConstrain($aRow,$aType,$aColor='black',$aArrowSize=ARROW_S2,$aArrowType=ARROWT_SOLID) { + $this->constraints[] = new GanttConstraint($aRow, $aType, $aColor, $aArrowSize, $aArrowType); + } + + function SetConstrainPos($xt,$yt,$xb,$yb) { + $this->iConstrainPos = array($xt,$yt,$xb,$yb); + } + + function GetMinDate() { + return $this->iStart; + } + + function GetMaxDate() { + return $this->iStart; + } + + function SetCaptionMargin($aMarg) { + $this->iCaptionMargin=$aMarg; + } + + function GetAbsHeight($aImg) { + return 0; + } + + function GetLineNbr() { + return $this->iVPos; + } + + function SetLabelLeftMargin($aOff) { + $this->iLabelLeftMargin=$aOff; + } + + function StrokeActInfo($aImg,$aScale,$aYPos) { + $cols=array(); + $aScale->actinfo->GetColStart($aImg,$cols,true); + $this->title->Stroke($aImg,$cols,$aYPos); + } +} + +//=================================================== +// CLASS Progress +// Holds parameters for the progress indicator +// displyed within a bar +//=================================================== +class Progress { + public $iProgress=-1; + public $iPattern=GANTT_SOLID; + public $iColor="black", $iFillColor='black'; + public $iDensity=98, $iHeight=0.65; + + function Set($aProg) { + if( $aProg < 0.0 || $aProg > 1.0 ) { + JpGraphError::RaiseL(6027); + //("Progress value must in range [0, 1]"); + } + $this->iProgress = $aProg; + } + + function SetPattern($aPattern,$aColor="blue",$aDensity=98) { + $this->iPattern = $aPattern; + $this->iColor = $aColor; + $this->iDensity = $aDensity; + } + + function SetFillColor($aColor) { + $this->iFillColor = $aColor; + } + + function SetHeight($aHeight) { + $this->iHeight = $aHeight; + } +} + +define('GANTT_HGRID1',0); +define('GANTT_HGRID2',1); + +//=================================================== +// CLASS HorizontalGridLine +// Responsible for drawinf horizontal gridlines and filled alternatibg rows +//=================================================== +class HorizontalGridLine { + private $iGraph=NULL; + private $iRowColor1 = '', $iRowColor2 = ''; + private $iShow=false; + private $line=null; + private $iStart=0; // 0=from left margin, 1=just along header + + function __construct() { + $this->line = new LineProperty(); + $this->line->SetColor('gray@0.4'); + $this->line->SetStyle('dashed'); + } + + function Show($aShow=true) { + $this->iShow = $aShow; + } + + function SetRowFillColor($aColor1,$aColor2='') { + $this->iRowColor1 = $aColor1; + $this->iRowColor2 = $aColor2; + } + + function SetStart($aStart) { + $this->iStart = $aStart; + } + + function Stroke($aImg,$aScale) { + + if( ! $this->iShow ) return; + + // Get horizontal width of line + /* + $limst = $aScale->iStartDate; + $limen = $aScale->iEndDate; + $xt = round($aScale->TranslateDate($aScale->iStartDate)); + $xb = round($aScale->TranslateDate($limen)); + */ + + if( $this->iStart === 0 ) { + $xt = $aImg->left_margin-1; + } + else { + $xt = round($aScale->TranslateDate($aScale->iStartDate))+1; + } + + $xb = $aImg->width-$aImg->right_margin; + + $yt = round($aScale->TranslateVertPos(0)); + $yb = round($aScale->TranslateVertPos(1)); + $height = $yb - $yt; + + // Loop around for all lines in the chart + for($i=0; $i < $aScale->iVertLines; ++$i ) { + $yb = $yt - $height; + $this->line->Stroke($aImg,$xt,$yb,$xb,$yb); + if( $this->iRowColor1 !== '' ) { + if( $i % 2 == 0 ) { + $aImg->PushColor($this->iRowColor1); + $aImg->FilledRectangle($xt,$yt,$xb,$yb); + $aImg->PopColor(); + } + elseif( $this->iRowColor2 !== '' ) { + $aImg->PushColor($this->iRowColor2); + $aImg->FilledRectangle($xt,$yt,$xb,$yb); + $aImg->PopColor(); + } + } + $yt = round($aScale->TranslateVertPos($i+1)); + } + $yb = $yt - $height; + $this->line->Stroke($aImg,$xt,$yb,$xb,$yb); + } +} + + +//=================================================== +// CLASS GanttBar +// Responsible for formatting individual gantt bars +//=================================================== +class GanttBar extends GanttPlotObject { + public $progress; + public $leftMark,$rightMark; + private $iEnd; + private $iHeightFactor=0.5; + private $iFillColor="white",$iFrameColor="black"; + private $iShadow=false,$iShadowColor="darkgray",$iShadowWidth=1,$iShadowFrame="black"; + private $iPattern=GANTT_RDIAG,$iPatternColor="blue",$iPatternDensity=95; + private $iBreakStyle=false, $iBreakLineStyle='dotted',$iBreakLineWeight=1; + //--------------- + // CONSTRUCTOR + function __construct($aPos,$aLabel,$aStart,$aEnd,$aCaption="",$aHeightFactor=0.6) { + parent::__construct(); + $this->iStart = $aStart; + // Is the end date given as a date or as number of days added to start date? + if( is_string($aEnd) ) { + // If end date has been specified without a time we will asssume + // end date is at the end of that date + if( strpos($aEnd,':') === false ) { + $this->iEnd = strtotime($aEnd)+SECPERDAY-1; + } + else { + $this->iEnd = $aEnd; + } + } + elseif(is_int($aEnd) || is_float($aEnd) ) { + $this->iEnd = strtotime($aStart)+round($aEnd*SECPERDAY); + } + $this->iVPos = $aPos; + $this->iHeightFactor = $aHeightFactor; + $this->title->Set($aLabel); + $this->caption = new TextProperty($aCaption); + $this->caption->Align("left","center"); + $this->leftMark =new PlotMark(); + $this->leftMark->Hide(); + $this->rightMark=new PlotMark(); + $this->rightMark->Hide(); + $this->progress = new Progress(); + } + + //--------------- + // PUBLIC METHODS + function SetShadow($aShadow=true,$aColor="gray") { + $this->iShadow=$aShadow; + $this->iShadowColor=$aColor; + } + + function SetBreakStyle($aFlg=true,$aLineStyle='dotted',$aLineWeight=1) { + $this->iBreakStyle = $aFlg; + $this->iBreakLineStyle = $aLineStyle; + $this->iBreakLineWeight = $aLineWeight; + } + + function GetMaxDate() { + return $this->iEnd; + } + + function SetHeight($aHeight) { + $this->iHeightFactor = $aHeight; + } + + function SetColor($aColor) { + $this->iFrameColor = $aColor; + } + + function SetFillColor($aColor) { + $this->iFillColor = $aColor; + } + + function GetAbsHeight($aImg) { + if( is_int($this->iHeightFactor) || $this->leftMark->show || $this->rightMark->show ) { + $m=-1; + if( is_int($this->iHeightFactor) ) + $m = $this->iHeightFactor; + if( $this->leftMark->show ) + $m = max($m,$this->leftMark->width*2); + if( $this->rightMark->show ) + $m = max($m,$this->rightMark->width*2); + return $m; + } + else + return -1; + } + + function SetPattern($aPattern,$aColor="blue",$aDensity=95) { + $this->iPattern = $aPattern; + $this->iPatternColor = $aColor; + $this->iPatternDensity = $aDensity; + } + + function Stroke($aImg,$aScale) { + $factory = new RectPatternFactory(); + $prect = $factory->Create($this->iPattern,$this->iPatternColor); + $prect->SetDensity($this->iPatternDensity); + + // If height factor is specified as a float between 0,1 then we take it as meaning + // percetage of the scale width between horizontal line. + // If it is an integer > 1 we take it to mean the absolute height in pixels + if( $this->iHeightFactor > -0.0 && $this->iHeightFactor <= 1.1) + $vs = $aScale->GetVertSpacing()*$this->iHeightFactor; + elseif(is_int($this->iHeightFactor) && $this->iHeightFactor>2 && $this->iHeightFactor < 200 ) + $vs = $this->iHeightFactor; + else { + JpGraphError::RaiseL(6028,$this->iHeightFactor); + // ("Specified height (".$this->iHeightFactor.") for gantt bar is out of range."); + } + + // Clip date to min max dates to show + $st = $aScale->NormalizeDate($this->iStart); + $en = $aScale->NormalizeDate($this->iEnd); + + $limst = max($st,$aScale->iStartDate); + $limen = min($en,$aScale->iEndDate); + + $xt = round($aScale->TranslateDate($limst)); + $xb = round($aScale->TranslateDate($limen)); + $yt = round($aScale->TranslateVertPos($this->iVPos)-$vs-($aScale->GetVertSpacing()/2-$vs/2)); + $yb = round($aScale->TranslateVertPos($this->iVPos)-($aScale->GetVertSpacing()/2-$vs/2)); + $middle = round($yt+($yb-$yt)/2); + $this->StrokeActInfo($aImg,$aScale,$middle); + + // CSIM for title + if( ! empty($this->title->csimtarget) ) { + $colwidth = $this->title->GetColWidth($aImg); + $colstarts=array(); + $aScale->actinfo->GetColStart($aImg,$colstarts,true); + $n = min(count($colwidth),count($this->title->csimtarget)); + for( $i=0; $i < $n; ++$i ) { + $title_xt = $colstarts[$i]; + $title_xb = $title_xt + $colwidth[$i]; + $coords = "$title_xt,$yt,$title_xb,$yt,$title_xb,$yb,$title_xt,$yb"; + + if( ! empty($this->title->csimtarget[$i]) ) { + $this->csimarea .= "title->csimtarget[$i]."\""; + + if( ! empty($this->title->csimwintarget[$i]) ) { + $this->csimarea .= "target=\"".$this->title->csimwintarget[$i]."\" "; + } + + if( ! empty($this->title->csimalt[$i]) ) { + $tmp = $this->title->csimalt[$i]; + $this->csimarea .= " title=\"$tmp\" alt=\"$tmp\" "; + } + $this->csimarea .= " />\n"; + } + } + } + + // Check if the bar is totally outside the current scale range + if( $en < $aScale->iStartDate || $st > $aScale->iEndDate ) + return; + + + // Remember the positions for the bar + $this->SetConstrainPos($xt,$yt,$xb,$yb); + + + + $prect->ShowFrame(false); + $prect->SetBackground($this->iFillColor); + if( $this->iBreakStyle ) { + $aImg->SetColor($this->iFrameColor); + $olds = $aImg->SetLineStyle($this->iBreakLineStyle); + $oldw = $aImg->SetLineWeight($this->iBreakLineWeight); + $aImg->StyleLine($xt,$yt,$xb,$yt); + $aImg->StyleLine($xt,$yb,$xb,$yb); + $aImg->SetLineStyle($olds); + $aImg->SetLineWeight($oldw); + } + else { + if( $this->iShadow ) { + $aImg->SetColor($this->iFrameColor); + $aImg->ShadowRectangle($xt,$yt,$xb,$yb,$this->iFillColor,$this->iShadowWidth,$this->iShadowColor); + $prect->SetPos(new Rectangle($xt+1,$yt+1,$xb-$xt-$this->iShadowWidth-2,$yb-$yt-$this->iShadowWidth-2)); + $prect->Stroke($aImg); + } + else { + $prect->SetPos(new Rectangle($xt,$yt,$xb-$xt+1,$yb-$yt+1)); + $prect->Stroke($aImg); + $aImg->SetColor($this->iFrameColor); + $aImg->Rectangle($xt,$yt,$xb,$yb); + } + } + // CSIM for bar + if( ! empty($this->csimtarget) ) { + + $coords = "$xt,$yt,$xb,$yt,$xb,$yb,$xt,$yb"; + $this->csimarea .= "csimtarget."\""; + + if( !empty($this->csimwintarget) ) { + $this->csimarea .= " target=\"".$this->csimwintarget."\" "; + } + + if( $this->csimalt != '' ) { + $tmp = $this->csimalt; + $this->csimarea .= " title=\"$tmp\" alt=\"$tmp\" "; + } + $this->csimarea .= " />\n"; + } + + // Draw progress bar inside activity bar + if( $this->progress->iProgress > 0 ) { + + $xtp = $aScale->TranslateDate($st); + $xbp = $aScale->TranslateDate($en); + $len = ($xbp-$xtp)*$this->progress->iProgress; + + $endpos = $xtp+$len; + if( $endpos > $xt ) { + + // Take away the length of the progress that is not visible (before the start date) + $len -= ($xt-$xtp); + + // Is the the progress bar visible after the start date? + if( $xtp < $xt ) + $xtp = $xt; + + // Make sure that the progess bar doesn't extend over the end date + if( $xtp+$len-1 > $xb ) + $len = $xb - $xtp ; + + $prog = $factory->Create($this->progress->iPattern,$this->progress->iColor); + $prog->SetDensity($this->progress->iDensity); + $prog->SetBackground($this->progress->iFillColor); + $barheight = ($yb-$yt+1); + if( $this->iShadow ) + $barheight -= $this->iShadowWidth; + $progressheight = floor($barheight*$this->progress->iHeight); + $marg = ceil(($barheight-$progressheight)/2); + $pos = new Rectangle($xtp,$yt + $marg, $len,$barheight-2*$marg); + $prog->SetPos($pos); + $prog->Stroke($aImg); + } + } + + // We don't plot the end mark if the bar has been capped + if( $limst == $st ) { + $y = $middle; + // We treat the RIGHT and LEFT triangle mark a little bi + // special so that these marks are placed right under the + // bar. + if( $this->leftMark->GetType() == MARK_LEFTTRIANGLE ) { + $y = $yb ; + } + $this->leftMark->Stroke($aImg,$xt,$y); + } + if( $limen == $en ) { + $y = $middle; + // We treat the RIGHT and LEFT triangle mark a little bi + // special so that these marks are placed right under the + // bar. + if( $this->rightMark->GetType() == MARK_RIGHTTRIANGLE ) { + $y = $yb ; + } + $this->rightMark->Stroke($aImg,$xb,$y); + + $margin = $this->iCaptionMargin; + if( $this->rightMark->show ) + $margin += $this->rightMark->GetWidth(); + $this->caption->Stroke($aImg,$xb+$margin,$middle); + } + } +} + +//=================================================== +// CLASS MileStone +// Responsible for formatting individual milestones +//=================================================== +class MileStone extends GanttPlotObject { + public $mark; + + //--------------- + // CONSTRUCTOR + function __construct($aVPos,$aLabel,$aDate,$aCaption="") { + GanttPlotObject::__construct(); + $this->caption->Set($aCaption); + $this->caption->Align("left","center"); + $this->caption->SetFont(FF_FONT1,FS_BOLD); + $this->title->Set($aLabel); + $this->title->SetColor("darkred"); + $this->mark = new PlotMark(); + $this->mark->SetWidth(10); + $this->mark->SetType(MARK_DIAMOND); + $this->mark->SetColor("darkred"); + $this->mark->SetFillColor("darkred"); + $this->iVPos = $aVPos; + $this->iStart = $aDate; + } + + //--------------- + // PUBLIC METHODS + + function GetAbsHeight($aImg) { + return max($this->title->GetHeight($aImg),$this->mark->GetWidth()); + } + + function Stroke($aImg,$aScale) { + // Put the mark in the middle at the middle of the day + $d = $aScale->NormalizeDate($this->iStart)+SECPERDAY/2; + $x = $aScale->TranslateDate($d); + $y = $aScale->TranslateVertPos($this->iVPos)-($aScale->GetVertSpacing()/2); + + $this->StrokeActInfo($aImg,$aScale,$y); + + // CSIM for title + if( ! empty($this->title->csimtarget) ) { + + $yt = round($y - $this->title->GetHeight($aImg)/2); + $yb = round($y + $this->title->GetHeight($aImg)/2); + + $colwidth = $this->title->GetColWidth($aImg); + $colstarts=array(); + $aScale->actinfo->GetColStart($aImg,$colstarts,true); + $n = min(count($colwidth),count($this->title->csimtarget)); + for( $i=0; $i < $n; ++$i ) { + $title_xt = $colstarts[$i]; + $title_xb = $title_xt + $colwidth[$i]; + $coords = "$title_xt,$yt,$title_xb,$yt,$title_xb,$yb,$title_xt,$yb"; + + if( !empty($this->title->csimtarget[$i]) ) { + + $this->csimarea .= "title->csimtarget[$i]."\""; + + if( !empty($this->title->csimwintarget[$i]) ) { + $this->csimarea .= "target=\"".$this->title->csimwintarget[$i]."\""; + } + + if( ! empty($this->title->csimalt[$i]) ) { + $tmp = $this->title->csimalt[$i]; + $this->csimarea .= " title=\"$tmp\" alt=\"$tmp\" "; + } + $this->csimarea .= " />\n"; + } + } + } + + if( $d < $aScale->iStartDate || $d > $aScale->iEndDate ) + return; + + // Remember the coordinates for any constrains linking to + // this milestone + $w = $this->mark->GetWidth()/2; + $this->SetConstrainPos($x,round($y-$w),$x,round($y+$w)); + + // Setup CSIM + if( $this->csimtarget != '' ) { + $this->mark->SetCSIMTarget( $this->csimtarget ); + $this->mark->SetCSIMAlt( $this->csimalt ); + } + + $this->mark->Stroke($aImg,$x,$y); + $this->caption->Stroke($aImg,$x+$this->mark->width/2+$this->iCaptionMargin,$y); + + $this->csimarea .= $this->mark->GetCSIMAreas(); + } +} + + +//=================================================== +// CLASS GanttVLine +// Responsible for formatting individual milestones +//=================================================== + +class TextPropertyBelow extends TextProperty { + function __construct($aTxt='') { + parent::__construct($aTxt); + } + + function GetColWidth($aImg,$aMargin=0) { + // Since we are not stroking the title in the columns + // but rather under the graph we want this to return 0. + return array(0); + } +} + +class GanttVLine extends GanttPlotObject { + + private $iLine,$title_margin=3, $iDayOffset=0.5; + private $iStartRow = -1, $iEndRow = -1; + + //--------------- + // CONSTRUCTOR + function __construct($aDate,$aTitle="",$aColor="darkred",$aWeight=2,$aStyle="solid") { + GanttPlotObject::__construct(); + $this->iLine = new LineProperty(); + $this->iLine->SetColor($aColor); + $this->iLine->SetWeight($aWeight); + $this->iLine->SetStyle($aStyle); + $this->iStart = $aDate; + $this->title = new TextPropertyBelow(); + $this->title->Set($aTitle); + } + + //--------------- + // PUBLIC METHODS + + // Set start and end rows for the VLine. By default the entire heigh of the + // Gantt chart is used + function SetRowSpan($aStart, $aEnd=-1) { + $this->iStartRow = $aStart; + $this->iEndRow = $aEnd; + } + + function SetDayOffset($aOff=0.5) { + if( $aOff < 0.0 || $aOff > 1.0 ) { + JpGraphError::RaiseL(6029); + //("Offset for vertical line must be in range [0,1]"); + } + $this->iDayOffset = $aOff; + } + + function SetTitleMargin($aMarg) { + $this->title_margin = $aMarg; + } + + function SetWeight($aWeight) { + $this->iLine->SetWeight($aWeight); + } + + function Stroke($aImg,$aScale) { + $d = $aScale->NormalizeDate($this->iStart); + if( $d < $aScale->iStartDate || $d > $aScale->iEndDate ) + return; + if($this->iDayOffset != 0.0) + $d += 24*60*60*$this->iDayOffset; + $x = $aScale->TranslateDate($d);//d=1006858800, + + if( $this->iStartRow > -1 ) { + $y1 = $aScale->TranslateVertPos($this->iStartRow,true) ; + } + else { + $y1 = $aScale->iVertHeaderSize+$aImg->top_margin; + } + + if( $this->iEndRow > -1 ) { + $y2 = $aScale->TranslateVertPos($this->iEndRow); + } + else { + $y2 = $aImg->height - $aImg->bottom_margin; + } + + $this->iLine->Stroke($aImg,$x,$y1,$x,$y2); + $this->title->Align("center","top"); + $this->title->Stroke($aImg,$x,$y2+$this->title_margin); + } +} + +//=================================================== +// CLASS LinkArrow +// Handles the drawing of a an arrow +//=================================================== +class LinkArrow { + private $ix,$iy; + private $isizespec = array( + array(2,3),array(3,5),array(3,8),array(6,15),array(8,22)); + private $iDirection=ARROW_DOWN,$iType=ARROWT_SOLID,$iSize=ARROW_S2; + private $iColor='black'; + + function __construct($x,$y,$aDirection,$aType=ARROWT_SOLID,$aSize=ARROW_S2) { + $this->iDirection = $aDirection; + $this->iType = $aType; + $this->iSize = $aSize; + $this->ix = $x; + $this->iy = $y; + } + + function SetColor($aColor) { + $this->iColor = $aColor; + } + + function SetSize($aSize) { + $this->iSize = $aSize; + } + + function SetType($aType) { + $this->iType = $aType; + } + + function Stroke($aImg) { + list($dx,$dy) = $this->isizespec[$this->iSize]; + $x = $this->ix; + $y = $this->iy; + switch ( $this->iDirection ) { + case ARROW_DOWN: + $c = array($x,$y,$x-$dx,$y-$dy,$x+$dx,$y-$dy,$x,$y); + break; + case ARROW_UP: + $c = array($x,$y,$x-$dx,$y+$dy,$x+$dx,$y+$dy,$x,$y); + break; + case ARROW_LEFT: + $c = array($x,$y,$x+$dy,$y-$dx,$x+$dy,$y+$dx,$x,$y); + break; + case ARROW_RIGHT: + $c = array($x,$y,$x-$dy,$y-$dx,$x-$dy,$y+$dx,$x,$y); + break; + default: + JpGraphError::RaiseL(6030); + //('Unknown arrow direction for link.'); + die(); + break; + } + $aImg->SetColor($this->iColor); + switch( $this->iType ) { + case ARROWT_SOLID: + $aImg->FilledPolygon($c); + break; + case ARROWT_OPEN: + $aImg->Polygon($c); + break; + default: + JpGraphError::RaiseL(6031); + //('Unknown arrow type for link.'); + die(); + break; + } + } +} + +//=================================================== +// CLASS GanttLink +// Handles the drawing of a link line between 2 points +//=================================================== + +class GanttLink { + private $ix1,$ix2,$iy1,$iy2; + private $iPathType=2,$iPathExtend=15; + private $iColor='black',$iWeight=1; + private $iArrowSize=ARROW_S2,$iArrowType=ARROWT_SOLID; + + function __construct($x1=0,$y1=0,$x2=0,$y2=0) { + $this->ix1 = $x1; + $this->ix2 = $x2; + $this->iy1 = $y1; + $this->iy2 = $y2; + } + + function SetPos($x1,$y1,$x2,$y2) { + $this->ix1 = $x1; + $this->ix2 = $x2; + $this->iy1 = $y1; + $this->iy2 = $y2; + } + + function SetPath($aPath) { + $this->iPathType = $aPath; + } + + function SetColor($aColor) { + $this->iColor = $aColor; + } + + function SetArrow($aSize,$aType=ARROWT_SOLID) { + $this->iArrowSize = $aSize; + $this->iArrowType = $aType; + } + + function SetWeight($aWeight) { + $this->iWeight = $aWeight; + } + + function Stroke($aImg) { + // The way the path for the arrow is constructed is partly based + // on some heuristics. This is not an exact science but draws the + // path in a way that, for me, makes esthetic sence. For example + // if the start and end activities are very close we make a small + // detour to endter the target horixontally. If there are more + // space between axctivities then no suh detour is made and the + // target is "hit" directly vertical. I have tried to keep this + // simple. no doubt this could become almost infinitive complex + // and have some real AI. Feel free to modify this. + // This will no-doubt be tweaked as times go by. One design aim + // is to avoid having the user choose what types of arrow + // he wants. + + // The arrow is drawn between (x1,y1) to (x2,y2) + $x1 = $this->ix1 ; + $x2 = $this->ix2 ; + $y1 = $this->iy1 ; + $y2 = $this->iy2 ; + + // Depending on if the target is below or above we have to + // handle thi different. + if( $y2 > $y1 ) { + $arrowtype = ARROW_DOWN; + $midy = round(($y2-$y1)/2+$y1); + if( $x2 > $x1 ) { + switch ( $this->iPathType ) { + case 0: + $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); + break; + case 1: + case 2: + case 3: + $c = array($x1,$y1,$x2,$y1,$x2,$y2); + break; + default: + JpGraphError::RaiseL(6032,$this->iPathType); + //('Internal error: Unknown path type (='.$this->iPathType .') specified for link.'); + exit(1); + break; + } + } + else { + switch ( $this->iPathType ) { + case 0: + case 1: + $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); + break; + case 2: + // Always extend out horizontally a bit from the first point + // If we draw a link back in time (end to start) and the bars + // are very close we also change the path so it comes in from + // the left on the activity + $c = array($x1,$y1,$x1+$this->iPathExtend,$y1, + $x1+$this->iPathExtend,$midy, + $x2,$midy,$x2,$y2); + break; + case 3: + if( $y2-$midy < 6 ) { + $c = array($x1,$y1,$x1,$midy, + $x2-$this->iPathExtend,$midy, + $x2-$this->iPathExtend,$y2, + $x2,$y2); + $arrowtype = ARROW_RIGHT; + } + else { + $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); + } + break; + default: + JpGraphError::RaiseL(6032,$this->iPathType); + //('Internal error: Unknown path type specified for link.'); + exit(1); + break; + } + } + $arrow = new LinkArrow($x2,$y2,$arrowtype); + } + else { + // Y2 < Y1 + $arrowtype = ARROW_UP; + $midy = round(($y1-$y2)/2+$y2); + if( $x2 > $x1 ) { + switch ( $this->iPathType ) { + case 0: + case 1: + $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); + break; + case 3: + if( $midy-$y2 < 8 ) { + $arrowtype = ARROW_RIGHT; + $c = array($x1,$y1,$x1,$y2,$x2,$y2); + } + else { + $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); + } + break; + default: + JpGraphError::RaiseL(6032,$this->iPathType); + //('Internal error: Unknown path type specified for link.'); + break; + } + } + else { + switch ( $this->iPathType ) { + case 0: + case 1: + $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); + break; + case 2: + // Always extend out horizontally a bit from the first point + $c = array($x1,$y1,$x1+$this->iPathExtend,$y1, + $x1+$this->iPathExtend,$midy, + $x2,$midy,$x2,$y2); + break; + case 3: + if( $midy-$y2 < 16 ) { + $arrowtype = ARROW_RIGHT; + $c = array($x1,$y1,$x1,$midy,$x2-$this->iPathExtend,$midy, + $x2-$this->iPathExtend,$y2, + $x2,$y2); + } + else { + $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); + } + break; + default: + JpGraphError::RaiseL(6032,$this->iPathType); + //('Internal error: Unknown path type specified for link.'); + break; + } + } + $arrow = new LinkArrow($x2,$y2,$arrowtype); + } + $aImg->SetColor($this->iColor); + $aImg->SetLineWeight($this->iWeight); + $aImg->Polygon($c); + $aImg->SetLineWeight(1); + $arrow->SetColor($this->iColor); + $arrow->SetSize($this->iArrowSize); + $arrow->SetType($this->iArrowType); + $arrow->Stroke($aImg); + } +} + +// +?> diff --git a/src/classes/jpgraph/jpgraph_gb2312.php b/src/classes/jpgraph/jpgraph_gb2312.php new file mode 100644 index 0000000..eff07cb --- /dev/null +++ b/src/classes/jpgraph/jpgraph_gb2312.php @@ -0,0 +1,1552 @@ + 12288, 8482 => 12289, 8483 => 12290, 8484 => 12539, 8485 => 713, + 8486 => 711, 8487 => 168, 8488 => 12291, 8489 => 12293, 8490 => 8213, + 8491 => 65374, 8492 => 8214, 8493 => 8230, 8494 => 8216, 8495 => 8217, + 8496 => 8220, 8497 => 8221, 8498 => 12308, 8499 => 12309, 8500 => 12296, + 8501 => 12297, 8502 => 12298, 8503 => 12299, 8504 => 12300, 8505 => 12301, + 8506 => 12302, 8507 => 12303, 8508 => 12310, 8509 => 12311, 8510 => 12304, + 8511 => 12305, 8512 => 177, 8513 => 215, 8514 => 247, 8515 => 8758, + 8516 => 8743, 8517 => 8744, 8518 => 8721, 8519 => 8719, 8520 => 8746, + 8521 => 8745, 8522 => 8712, 8523 => 8759, 8524 => 8730, 8525 => 8869, + 8526 => 8741, 8527 => 8736, 8528 => 8978, 8529 => 8857, 8530 => 8747, + 8531 => 8750, 8532 => 8801, 8533 => 8780, 8534 => 8776, 8535 => 8765, + 8536 => 8733, 8537 => 8800, 8538 => 8814, 8539 => 8815, 8540 => 8804, + 8541 => 8805, 8542 => 8734, 8543 => 8757, 8544 => 8756, 8545 => 9794, + 8546 => 9792, 8547 => 176, 8548 => 8242, 8549 => 8243, 8550 => 8451, + 8551 => 65284, 8552 => 164, 8553 => 65504, 8554 => 65505, 8555 => 8240, + 8556 => 167, 8557 => 8470, 8558 => 9734, 8559 => 9733, 8560 => 9675, + 8561 => 9679, 8562 => 9678, 8563 => 9671, 8564 => 9670, 8565 => 9633, + 8566 => 9632, 8567 => 9651, 8568 => 9650, 8569 => 8251, 8570 => 8594, + 8571 => 8592, 8572 => 8593, 8573 => 8595, 8574 => 12307, 8753 => 9352, + 8754 => 9353, 8755 => 9354, 8756 => 9355, 8757 => 9356, 8758 => 9357, + 8759 => 9358, 8760 => 9359, 8761 => 9360, 8762 => 9361, 8763 => 9362, + 8764 => 9363, 8765 => 9364, 8766 => 9365, 8767 => 9366, 8768 => 9367, + 8769 => 9368, 8770 => 9369, 8771 => 9370, 8772 => 9371, 8773 => 9332, + 8774 => 9333, 8775 => 9334, 8776 => 9335, 8777 => 9336, 8778 => 9337, + 8779 => 9338, 8780 => 9339, 8781 => 9340, 8782 => 9341, 8783 => 9342, + 8784 => 9343, 8785 => 9344, 8786 => 9345, 8787 => 9346, 8788 => 9347, + 8789 => 9348, 8790 => 9349, 8791 => 9350, 8792 => 9351, 8793 => 9312, + 8794 => 9313, 8795 => 9314, 8796 => 9315, 8797 => 9316, 8798 => 9317, + 8799 => 9318, 8800 => 9319, 8801 => 9320, 8802 => 9321, 8805 => 12832, + 8806 => 12833, 8807 => 12834, 8808 => 12835, 8809 => 12836, 8810 => 12837, + 8811 => 12838, 8812 => 12839, 8813 => 12840, 8814 => 12841, 8817 => 8544, + 8818 => 8545, 8819 => 8546, 8820 => 8547, 8821 => 8548, 8822 => 8549, + 8823 => 8550, 8824 => 8551, 8825 => 8552, 8826 => 8553, 8827 => 8554, + 8828 => 8555, 8993 => 65281, 8994 => 65282, 8995 => 65283, 8996 => 65509, + 8997 => 65285, 8998 => 65286, 8999 => 65287, 9000 => 65288, 9001 => 65289, + 9002 => 65290, 9003 => 65291, 9004 => 65292, 9005 => 65293, 9006 => 65294, + 9007 => 65295, 9008 => 65296, 9009 => 65297, 9010 => 65298, 9011 => 65299, + 9012 => 65300, 9013 => 65301, 9014 => 65302, 9015 => 65303, 9016 => 65304, + 9017 => 65305, 9018 => 65306, 9019 => 65307, 9020 => 65308, 9021 => 65309, + 9022 => 65310, 9023 => 65311, 9024 => 65312, 9025 => 65313, 9026 => 65314, + 9027 => 65315, 9028 => 65316, 9029 => 65317, 9030 => 65318, 9031 => 65319, + 9032 => 65320, 9033 => 65321, 9034 => 65322, 9035 => 65323, 9036 => 65324, + 9037 => 65325, 9038 => 65326, 9039 => 65327, 9040 => 65328, 9041 => 65329, + 9042 => 65330, 9043 => 65331, 9044 => 65332, 9045 => 65333, 9046 => 65334, + 9047 => 65335, 9048 => 65336, 9049 => 65337, 9050 => 65338, 9051 => 65339, + 9052 => 65340, 9053 => 65341, 9054 => 65342, 9055 => 65343, 9056 => 65344, + 9057 => 65345, 9058 => 65346, 9059 => 65347, 9060 => 65348, 9061 => 65349, + 9062 => 65350, 9063 => 65351, 9064 => 65352, 9065 => 65353, 9066 => 65354, + 9067 => 65355, 9068 => 65356, 9069 => 65357, 9070 => 65358, 9071 => 65359, + 9072 => 65360, 9073 => 65361, 9074 => 65362, 9075 => 65363, 9076 => 65364, + 9077 => 65365, 9078 => 65366, 9079 => 65367, 9080 => 65368, 9081 => 65369, + 9082 => 65370, 9083 => 65371, 9084 => 65372, 9085 => 65373, 9086 => 65507, + 9249 => 12353, 9250 => 12354, 9251 => 12355, 9252 => 12356, 9253 => 12357, + 9254 => 12358, 9255 => 12359, 9256 => 12360, 9257 => 12361, 9258 => 12362, + 9259 => 12363, 9260 => 12364, 9261 => 12365, 9262 => 12366, 9263 => 12367, + 9264 => 12368, 9265 => 12369, 9266 => 12370, 9267 => 12371, 9268 => 12372, + 9269 => 12373, 9270 => 12374, 9271 => 12375, 9272 => 12376, 9273 => 12377, + 9274 => 12378, 9275 => 12379, 9276 => 12380, 9277 => 12381, 9278 => 12382, + 9279 => 12383, 9280 => 12384, 9281 => 12385, 9282 => 12386, 9283 => 12387, + 9284 => 12388, 9285 => 12389, 9286 => 12390, 9287 => 12391, 9288 => 12392, + 9289 => 12393, 9290 => 12394, 9291 => 12395, 9292 => 12396, 9293 => 12397, + 9294 => 12398, 9295 => 12399, 9296 => 12400, 9297 => 12401, 9298 => 12402, + 9299 => 12403, 9300 => 12404, 9301 => 12405, 9302 => 12406, 9303 => 12407, + 9304 => 12408, 9305 => 12409, 9306 => 12410, 9307 => 12411, 9308 => 12412, + 9309 => 12413, 9310 => 12414, 9311 => 12415, 9312 => 12416, 9313 => 12417, + 9314 => 12418, 9315 => 12419, 9316 => 12420, 9317 => 12421, 9318 => 12422, + 9319 => 12423, 9320 => 12424, 9321 => 12425, 9322 => 12426, 9323 => 12427, + 9324 => 12428, 9325 => 12429, 9326 => 12430, 9327 => 12431, 9328 => 12432, + 9329 => 12433, 9330 => 12434, 9331 => 12435, 9505 => 12449, 9506 => 12450, + 9507 => 12451, 9508 => 12452, 9509 => 12453, 9510 => 12454, 9511 => 12455, + 9512 => 12456, 9513 => 12457, 9514 => 12458, 9515 => 12459, 9516 => 12460, + 9517 => 12461, 9518 => 12462, 9519 => 12463, 9520 => 12464, 9521 => 12465, + 9522 => 12466, 9523 => 12467, 9524 => 12468, 9525 => 12469, 9526 => 12470, + 9527 => 12471, 9528 => 12472, 9529 => 12473, 9530 => 12474, 9531 => 12475, + 9532 => 12476, 9533 => 12477, 9534 => 12478, 9535 => 12479, 9536 => 12480, + 9537 => 12481, 9538 => 12482, 9539 => 12483, 9540 => 12484, 9541 => 12485, + 9542 => 12486, 9543 => 12487, 9544 => 12488, 9545 => 12489, 9546 => 12490, + 9547 => 12491, 9548 => 12492, 9549 => 12493, 9550 => 12494, 9551 => 12495, + 9552 => 12496, 9553 => 12497, 9554 => 12498, 9555 => 12499, 9556 => 12500, + 9557 => 12501, 9558 => 12502, 9559 => 12503, 9560 => 12504, 9561 => 12505, + 9562 => 12506, 9563 => 12507, 9564 => 12508, 9565 => 12509, 9566 => 12510, + 9567 => 12511, 9568 => 12512, 9569 => 12513, 9570 => 12514, 9571 => 12515, + 9572 => 12516, 9573 => 12517, 9574 => 12518, 9575 => 12519, 9576 => 12520, + 9577 => 12521, 9578 => 12522, 9579 => 12523, 9580 => 12524, 9581 => 12525, + 9582 => 12526, 9583 => 12527, 9584 => 12528, 9585 => 12529, 9586 => 12530, + 9587 => 12531, 9588 => 12532, 9589 => 12533, 9590 => 12534, 9761 => 913, + 9762 => 914, 9763 => 915, 9764 => 916, 9765 => 917, 9766 => 918, + 9767 => 919, 9768 => 920, 9769 => 921, 9770 => 922, 9771 => 923, + 9772 => 924, 9773 => 925, 9774 => 926, 9775 => 927, 9776 => 928, + 9777 => 929, 9778 => 931, 9779 => 932, 9780 => 933, 9781 => 934, + 9782 => 935, 9783 => 936, 9784 => 937, 9793 => 945, 9794 => 946, + 9795 => 947, 9796 => 948, 9797 => 949, 9798 => 950, 9799 => 951, + 9800 => 952, 9801 => 953, 9802 => 954, 9803 => 955, 9804 => 956, + 9805 => 957, 9806 => 958, 9807 => 959, 9808 => 960, 9809 => 961, + 9810 => 963, 9811 => 964, 9812 => 965, 9813 => 966, 9814 => 967, + 9815 => 968, 9816 => 969, 10017 => 1040, 10018 => 1041, 10019 => 1042, + 10020 => 1043, 10021 => 1044, 10022 => 1045, 10023 => 1025, 10024 => 1046, + 10025 => 1047, 10026 => 1048, 10027 => 1049, 10028 => 1050, 10029 => 1051, + 10030 => 1052, 10031 => 1053, 10032 => 1054, 10033 => 1055, 10034 => 1056, + 10035 => 1057, 10036 => 1058, 10037 => 1059, 10038 => 1060, 10039 => 1061, + 10040 => 1062, 10041 => 1063, 10042 => 1064, 10043 => 1065, 10044 => 1066, + 10045 => 1067, 10046 => 1068, 10047 => 1069, 10048 => 1070, 10049 => 1071, + 10065 => 1072, 10066 => 1073, 10067 => 1074, 10068 => 1075, 10069 => 1076, + 10070 => 1077, 10071 => 1105, 10072 => 1078, 10073 => 1079, 10074 => 1080, + 10075 => 1081, 10076 => 1082, 10077 => 1083, 10078 => 1084, 10079 => 1085, + 10080 => 1086, 10081 => 1087, 10082 => 1088, 10083 => 1089, 10084 => 1090, + 10085 => 1091, 10086 => 1092, 10087 => 1093, 10088 => 1094, 10089 => 1095, + 10090 => 1096, 10091 => 1097, 10092 => 1098, 10093 => 1099, 10094 => 1100, + 10095 => 1101, 10096 => 1102, 10097 => 1103, 10273 => 257, 10274 => 225, + 10275 => 462, 10276 => 224, 10277 => 275, 10278 => 233, 10279 => 283, + 10280 => 232, 10281 => 299, 10282 => 237, 10283 => 464, 10284 => 236, + 10285 => 333, 10286 => 243, 10287 => 466, 10288 => 242, 10289 => 363, + 10290 => 250, 10291 => 468, 10292 => 249, 10293 => 470, 10294 => 472, + 10295 => 474, 10296 => 476, 10297 => 252, 10298 => 234, 10309 => 12549, + 10310 => 12550, 10311 => 12551, 10312 => 12552, 10313 => 12553, 10314 => 12554, + 10315 => 12555, 10316 => 12556, 10317 => 12557, 10318 => 12558, 10319 => 12559, + 10320 => 12560, 10321 => 12561, 10322 => 12562, 10323 => 12563, 10324 => 12564, + 10325 => 12565, 10326 => 12566, 10327 => 12567, 10328 => 12568, 10329 => 12569, + 10330 => 12570, 10331 => 12571, 10332 => 12572, 10333 => 12573, 10334 => 12574, + 10335 => 12575, 10336 => 12576, 10337 => 12577, 10338 => 12578, 10339 => 12579, + 10340 => 12580, 10341 => 12581, 10342 => 12582, 10343 => 12583, 10344 => 12584, + 10345 => 12585, 10532 => 9472, 10533 => 9473, 10534 => 9474, 10535 => 9475, + 10536 => 9476, 10537 => 9477, 10538 => 9478, 10539 => 9479, 10540 => 9480, + 10541 => 9481, 10542 => 9482, 10543 => 9483, 10544 => 9484, 10545 => 9485, + 10546 => 9486, 10547 => 9487, 10548 => 9488, 10549 => 9489, 10550 => 9490, + 10551 => 9491, 10552 => 9492, 10553 => 9493, 10554 => 9494, 10555 => 9495, + 10556 => 9496, 10557 => 9497, 10558 => 9498, 10559 => 9499, 10560 => 9500, + 10561 => 9501, 10562 => 9502, 10563 => 9503, 10564 => 9504, 10565 => 9505, + 10566 => 9506, 10567 => 9507, 10568 => 9508, 10569 => 9509, 10570 => 9510, + 10571 => 9511, 10572 => 9512, 10573 => 9513, 10574 => 9514, 10575 => 9515, + 10576 => 9516, 10577 => 9517, 10578 => 9518, 10579 => 9519, 10580 => 9520, + 10581 => 9521, 10582 => 9522, 10583 => 9523, 10584 => 9524, 10585 => 9525, + 10586 => 9526, 10587 => 9527, 10588 => 9528, 10589 => 9529, 10590 => 9530, + 10591 => 9531, 10592 => 9532, 10593 => 9533, 10594 => 9534, 10595 => 9535, + 10596 => 9536, 10597 => 9537, 10598 => 9538, 10599 => 9539, 10600 => 9540, + 10601 => 9541, 10602 => 9542, 10603 => 9543, 10604 => 9544, 10605 => 9545, + 10606 => 9546, 10607 => 9547, 12321 => 21834, 12322 => 38463, 12323 => 22467, + 12324 => 25384, 12325 => 21710, 12326 => 21769, 12327 => 21696, 12328 => 30353, + 12329 => 30284, 12330 => 34108, 12331 => 30702, 12332 => 33406, 12333 => 30861, + 12334 => 29233, 12335 => 38552, 12336 => 38797, 12337 => 27688, 12338 => 23433, + 12339 => 20474, 12340 => 25353, 12341 => 26263, 12342 => 23736, 12343 => 33018, + 12344 => 26696, 12345 => 32942, 12346 => 26114, 12347 => 30414, 12348 => 20985, + 12349 => 25942, 12350 => 29100, 12351 => 32753, 12352 => 34948, 12353 => 20658, + 12354 => 22885, 12355 => 25034, 12356 => 28595, 12357 => 33453, 12358 => 25420, + 12359 => 25170, 12360 => 21485, 12361 => 21543, 12362 => 31494, 12363 => 20843, + 12364 => 30116, 12365 => 24052, 12366 => 25300, 12367 => 36299, 12368 => 38774, + 12369 => 25226, 12370 => 32793, 12371 => 22365, 12372 => 38712, 12373 => 32610, + 12374 => 29240, 12375 => 30333, 12376 => 26575, 12377 => 30334, 12378 => 25670, + 12379 => 20336, 12380 => 36133, 12381 => 25308, 12382 => 31255, 12383 => 26001, + 12384 => 29677, 12385 => 25644, 12386 => 25203, 12387 => 33324, 12388 => 39041, + 12389 => 26495, 12390 => 29256, 12391 => 25198, 12392 => 25292, 12393 => 20276, + 12394 => 29923, 12395 => 21322, 12396 => 21150, 12397 => 32458, 12398 => 37030, + 12399 => 24110, 12400 => 26758, 12401 => 27036, 12402 => 33152, 12403 => 32465, + 12404 => 26834, 12405 => 30917, 12406 => 34444, 12407 => 38225, 12408 => 20621, + 12409 => 35876, 12410 => 33502, 12411 => 32990, 12412 => 21253, 12413 => 35090, + 12414 => 21093, 12577 => 34180, 12578 => 38649, 12579 => 20445, 12580 => 22561, + 12581 => 39281, 12582 => 23453, 12583 => 25265, 12584 => 25253, 12585 => 26292, + 12586 => 35961, 12587 => 40077, 12588 => 29190, 12589 => 26479, 12590 => 30865, + 12591 => 24754, 12592 => 21329, 12593 => 21271, 12594 => 36744, 12595 => 32972, + 12596 => 36125, 12597 => 38049, 12598 => 20493, 12599 => 29384, 12600 => 22791, + 12601 => 24811, 12602 => 28953, 12603 => 34987, 12604 => 22868, 12605 => 33519, + 12606 => 26412, 12607 => 31528, 12608 => 23849, 12609 => 32503, 12610 => 29997, + 12611 => 27893, 12612 => 36454, 12613 => 36856, 12614 => 36924, 12615 => 40763, + 12616 => 27604, 12617 => 37145, 12618 => 31508, 12619 => 24444, 12620 => 30887, + 12621 => 34006, 12622 => 34109, 12623 => 27605, 12624 => 27609, 12625 => 27606, + 12626 => 24065, 12627 => 24199, 12628 => 30201, 12629 => 38381, 12630 => 25949, + 12631 => 24330, 12632 => 24517, 12633 => 36767, 12634 => 22721, 12635 => 33218, + 12636 => 36991, 12637 => 38491, 12638 => 38829, 12639 => 36793, 12640 => 32534, + 12641 => 36140, 12642 => 25153, 12643 => 20415, 12644 => 21464, 12645 => 21342, + 12646 => 36776, 12647 => 36777, 12648 => 36779, 12649 => 36941, 12650 => 26631, + 12651 => 24426, 12652 => 33176, 12653 => 34920, 12654 => 40150, 12655 => 24971, + 12656 => 21035, 12657 => 30250, 12658 => 24428, 12659 => 25996, 12660 => 28626, + 12661 => 28392, 12662 => 23486, 12663 => 25672, 12664 => 20853, 12665 => 20912, + 12666 => 26564, 12667 => 19993, 12668 => 31177, 12669 => 39292, 12670 => 28851, + 12833 => 30149, 12834 => 24182, 12835 => 29627, 12836 => 33760, 12837 => 25773, + 12838 => 25320, 12839 => 38069, 12840 => 27874, 12841 => 21338, 12842 => 21187, + 12843 => 25615, 12844 => 38082, 12845 => 31636, 12846 => 20271, 12847 => 24091, + 12848 => 33334, 12849 => 33046, 12850 => 33162, 12851 => 28196, 12852 => 27850, + 12853 => 39539, 12854 => 25429, 12855 => 21340, 12856 => 21754, 12857 => 34917, + 12858 => 22496, 12859 => 19981, 12860 => 24067, 12861 => 27493, 12862 => 31807, + 12863 => 37096, 12864 => 24598, 12865 => 25830, 12866 => 29468, 12867 => 35009, + 12868 => 26448, 12869 => 25165, 12870 => 36130, 12871 => 30572, 12872 => 36393, + 12873 => 37319, 12874 => 24425, 12875 => 33756, 12876 => 34081, 12877 => 39184, + 12878 => 21442, 12879 => 34453, 12880 => 27531, 12881 => 24813, 12882 => 24808, + 12883 => 28799, 12884 => 33485, 12885 => 33329, 12886 => 20179, 12887 => 27815, + 12888 => 34255, 12889 => 25805, 12890 => 31961, 12891 => 27133, 12892 => 26361, + 12893 => 33609, 12894 => 21397, 12895 => 31574, 12896 => 20391, 12897 => 20876, + 12898 => 27979, 12899 => 23618, 12900 => 36461, 12901 => 25554, 12902 => 21449, + 12903 => 33580, 12904 => 33590, 12905 => 26597, 12906 => 30900, 12907 => 25661, + 12908 => 23519, 12909 => 23700, 12910 => 24046, 12911 => 35815, 12912 => 25286, + 12913 => 26612, 12914 => 35962, 12915 => 25600, 12916 => 25530, 12917 => 34633, + 12918 => 39307, 12919 => 35863, 12920 => 32544, 12921 => 38130, 12922 => 20135, + 12923 => 38416, 12924 => 39076, 12925 => 26124, 12926 => 29462, 13089 => 22330, + 13090 => 23581, 13091 => 24120, 13092 => 38271, 13093 => 20607, 13094 => 32928, + 13095 => 21378, 13096 => 25950, 13097 => 30021, 13098 => 21809, 13099 => 20513, + 13100 => 36229, 13101 => 25220, 13102 => 38046, 13103 => 26397, 13104 => 22066, + 13105 => 28526, 13106 => 24034, 13107 => 21557, 13108 => 28818, 13109 => 36710, + 13110 => 25199, 13111 => 25764, 13112 => 25507, 13113 => 24443, 13114 => 28552, + 13115 => 37108, 13116 => 33251, 13117 => 36784, 13118 => 23576, 13119 => 26216, + 13120 => 24561, 13121 => 27785, 13122 => 38472, 13123 => 36225, 13124 => 34924, + 13125 => 25745, 13126 => 31216, 13127 => 22478, 13128 => 27225, 13129 => 25104, + 13130 => 21576, 13131 => 20056, 13132 => 31243, 13133 => 24809, 13134 => 28548, + 13135 => 35802, 13136 => 25215, 13137 => 36894, 13138 => 39563, 13139 => 31204, + 13140 => 21507, 13141 => 30196, 13142 => 25345, 13143 => 21273, 13144 => 27744, + 13145 => 36831, 13146 => 24347, 13147 => 39536, 13148 => 32827, 13149 => 40831, + 13150 => 20360, 13151 => 23610, 13152 => 36196, 13153 => 32709, 13154 => 26021, + 13155 => 28861, 13156 => 20805, 13157 => 20914, 13158 => 34411, 13159 => 23815, + 13160 => 23456, 13161 => 25277, 13162 => 37228, 13163 => 30068, 13164 => 36364, + 13165 => 31264, 13166 => 24833, 13167 => 31609, 13168 => 20167, 13169 => 32504, + 13170 => 30597, 13171 => 19985, 13172 => 33261, 13173 => 21021, 13174 => 20986, + 13175 => 27249, 13176 => 21416, 13177 => 36487, 13178 => 38148, 13179 => 38607, + 13180 => 28353, 13181 => 38500, 13182 => 26970, 13345 => 30784, 13346 => 20648, + 13347 => 30679, 13348 => 25616, 13349 => 35302, 13350 => 22788, 13351 => 25571, + 13352 => 24029, 13353 => 31359, 13354 => 26941, 13355 => 20256, 13356 => 33337, + 13357 => 21912, 13358 => 20018, 13359 => 30126, 13360 => 31383, 13361 => 24162, + 13362 => 24202, 13363 => 38383, 13364 => 21019, 13365 => 21561, 13366 => 28810, + 13367 => 25462, 13368 => 38180, 13369 => 22402, 13370 => 26149, 13371 => 26943, + 13372 => 37255, 13373 => 21767, 13374 => 28147, 13375 => 32431, 13376 => 34850, + 13377 => 25139, 13378 => 32496, 13379 => 30133, 13380 => 33576, 13381 => 30913, + 13382 => 38604, 13383 => 36766, 13384 => 24904, 13385 => 29943, 13386 => 35789, + 13387 => 27492, 13388 => 21050, 13389 => 36176, 13390 => 27425, 13391 => 32874, + 13392 => 33905, 13393 => 22257, 13394 => 21254, 13395 => 20174, 13396 => 19995, + 13397 => 20945, 13398 => 31895, 13399 => 37259, 13400 => 31751, 13401 => 20419, + 13402 => 36479, 13403 => 31713, 13404 => 31388, 13405 => 25703, 13406 => 23828, + 13407 => 20652, 13408 => 33030, 13409 => 30209, 13410 => 31929, 13411 => 28140, + 13412 => 32736, 13413 => 26449, 13414 => 23384, 13415 => 23544, 13416 => 30923, + 13417 => 25774, 13418 => 25619, 13419 => 25514, 13420 => 25387, 13421 => 38169, + 13422 => 25645, 13423 => 36798, 13424 => 31572, 13425 => 30249, 13426 => 25171, + 13427 => 22823, 13428 => 21574, 13429 => 27513, 13430 => 20643, 13431 => 25140, + 13432 => 24102, 13433 => 27526, 13434 => 20195, 13435 => 36151, 13436 => 34955, + 13437 => 24453, 13438 => 36910, 13601 => 24608, 13602 => 32829, 13603 => 25285, + 13604 => 20025, 13605 => 21333, 13606 => 37112, 13607 => 25528, 13608 => 32966, + 13609 => 26086, 13610 => 27694, 13611 => 20294, 13612 => 24814, 13613 => 28129, + 13614 => 35806, 13615 => 24377, 13616 => 34507, 13617 => 24403, 13618 => 25377, + 13619 => 20826, 13620 => 33633, 13621 => 26723, 13622 => 20992, 13623 => 25443, + 13624 => 36424, 13625 => 20498, 13626 => 23707, 13627 => 31095, 13628 => 23548, + 13629 => 21040, 13630 => 31291, 13631 => 24764, 13632 => 36947, 13633 => 30423, + 13634 => 24503, 13635 => 24471, 13636 => 30340, 13637 => 36460, 13638 => 28783, + 13639 => 30331, 13640 => 31561, 13641 => 30634, 13642 => 20979, 13643 => 37011, + 13644 => 22564, 13645 => 20302, 13646 => 28404, 13647 => 36842, 13648 => 25932, + 13649 => 31515, 13650 => 29380, 13651 => 28068, 13652 => 32735, 13653 => 23265, + 13654 => 25269, 13655 => 24213, 13656 => 22320, 13657 => 33922, 13658 => 31532, + 13659 => 24093, 13660 => 24351, 13661 => 36882, 13662 => 32532, 13663 => 39072, + 13664 => 25474, 13665 => 28359, 13666 => 30872, 13667 => 28857, 13668 => 20856, + 13669 => 38747, 13670 => 22443, 13671 => 30005, 13672 => 20291, 13673 => 30008, + 13674 => 24215, 13675 => 24806, 13676 => 22880, 13677 => 28096, 13678 => 27583, + 13679 => 30857, 13680 => 21500, 13681 => 38613, 13682 => 20939, 13683 => 20993, + 13684 => 25481, 13685 => 21514, 13686 => 38035, 13687 => 35843, 13688 => 36300, + 13689 => 29241, 13690 => 30879, 13691 => 34678, 13692 => 36845, 13693 => 35853, + 13694 => 21472, 13857 => 19969, 13858 => 30447, 13859 => 21486, 13860 => 38025, + 13861 => 39030, 13862 => 40718, 13863 => 38189, 13864 => 23450, 13865 => 35746, + 13866 => 20002, 13867 => 19996, 13868 => 20908, 13869 => 33891, 13870 => 25026, + 13871 => 21160, 13872 => 26635, 13873 => 20375, 13874 => 24683, 13875 => 20923, + 13876 => 27934, 13877 => 20828, 13878 => 25238, 13879 => 26007, 13880 => 38497, + 13881 => 35910, 13882 => 36887, 13883 => 30168, 13884 => 37117, 13885 => 30563, + 13886 => 27602, 13887 => 29322, 13888 => 29420, 13889 => 35835, 13890 => 22581, + 13891 => 30585, 13892 => 36172, 13893 => 26460, 13894 => 38208, 13895 => 32922, + 13896 => 24230, 13897 => 28193, 13898 => 22930, 13899 => 31471, 13900 => 30701, + 13901 => 38203, 13902 => 27573, 13903 => 26029, 13904 => 32526, 13905 => 22534, + 13906 => 20817, 13907 => 38431, 13908 => 23545, 13909 => 22697, 13910 => 21544, + 13911 => 36466, 13912 => 25958, 13913 => 39039, 13914 => 22244, 13915 => 38045, + 13916 => 30462, 13917 => 36929, 13918 => 25479, 13919 => 21702, 13920 => 22810, + 13921 => 22842, 13922 => 22427, 13923 => 36530, 13924 => 26421, 13925 => 36346, + 13926 => 33333, 13927 => 21057, 13928 => 24816, 13929 => 22549, 13930 => 34558, + 13931 => 23784, 13932 => 40517, 13933 => 20420, 13934 => 39069, 13935 => 35769, + 13936 => 23077, 13937 => 24694, 13938 => 21380, 13939 => 25212, 13940 => 36943, + 13941 => 37122, 13942 => 39295, 13943 => 24681, 13944 => 32780, 13945 => 20799, + 13946 => 32819, 13947 => 23572, 13948 => 39285, 13949 => 27953, 13950 => 20108, + 14113 => 36144, 14114 => 21457, 14115 => 32602, 14116 => 31567, 14117 => 20240, + 14118 => 20047, 14119 => 38400, 14120 => 27861, 14121 => 29648, 14122 => 34281, + 14123 => 24070, 14124 => 30058, 14125 => 32763, 14126 => 27146, 14127 => 30718, + 14128 => 38034, 14129 => 32321, 14130 => 20961, 14131 => 28902, 14132 => 21453, + 14133 => 36820, 14134 => 33539, 14135 => 36137, 14136 => 29359, 14137 => 39277, + 14138 => 27867, 14139 => 22346, 14140 => 33459, 14141 => 26041, 14142 => 32938, + 14143 => 25151, 14144 => 38450, 14145 => 22952, 14146 => 20223, 14147 => 35775, + 14148 => 32442, 14149 => 25918, 14150 => 33778, 14151 => 38750, 14152 => 21857, + 14153 => 39134, 14154 => 32933, 14155 => 21290, 14156 => 35837, 14157 => 21536, + 14158 => 32954, 14159 => 24223, 14160 => 27832, 14161 => 36153, 14162 => 33452, + 14163 => 37210, 14164 => 21545, 14165 => 27675, 14166 => 20998, 14167 => 32439, + 14168 => 22367, 14169 => 28954, 14170 => 27774, 14171 => 31881, 14172 => 22859, + 14173 => 20221, 14174 => 24575, 14175 => 24868, 14176 => 31914, 14177 => 20016, + 14178 => 23553, 14179 => 26539, 14180 => 34562, 14181 => 23792, 14182 => 38155, + 14183 => 39118, 14184 => 30127, 14185 => 28925, 14186 => 36898, 14187 => 20911, + 14188 => 32541, 14189 => 35773, 14190 => 22857, 14191 => 20964, 14192 => 20315, + 14193 => 21542, 14194 => 22827, 14195 => 25975, 14196 => 32932, 14197 => 23413, + 14198 => 25206, 14199 => 25282, 14200 => 36752, 14201 => 24133, 14202 => 27679, + 14203 => 31526, 14204 => 20239, 14205 => 20440, 14206 => 26381, 14369 => 28014, + 14370 => 28074, 14371 => 31119, 14372 => 34993, 14373 => 24343, 14374 => 29995, + 14375 => 25242, 14376 => 36741, 14377 => 20463, 14378 => 37340, 14379 => 26023, + 14380 => 33071, 14381 => 33105, 14382 => 24220, 14383 => 33104, 14384 => 36212, + 14385 => 21103, 14386 => 35206, 14387 => 36171, 14388 => 22797, 14389 => 20613, + 14390 => 20184, 14391 => 38428, 14392 => 29238, 14393 => 33145, 14394 => 36127, + 14395 => 23500, 14396 => 35747, 14397 => 38468, 14398 => 22919, 14399 => 32538, + 14400 => 21648, 14401 => 22134, 14402 => 22030, 14403 => 35813, 14404 => 25913, + 14405 => 27010, 14406 => 38041, 14407 => 30422, 14408 => 28297, 14409 => 24178, + 14410 => 29976, 14411 => 26438, 14412 => 26577, 14413 => 31487, 14414 => 32925, + 14415 => 36214, 14416 => 24863, 14417 => 31174, 14418 => 25954, 14419 => 36195, + 14420 => 20872, 14421 => 21018, 14422 => 38050, 14423 => 32568, 14424 => 32923, + 14425 => 32434, 14426 => 23703, 14427 => 28207, 14428 => 26464, 14429 => 31705, + 14430 => 30347, 14431 => 39640, 14432 => 33167, 14433 => 32660, 14434 => 31957, + 14435 => 25630, 14436 => 38224, 14437 => 31295, 14438 => 21578, 14439 => 21733, + 14440 => 27468, 14441 => 25601, 14442 => 25096, 14443 => 40509, 14444 => 33011, + 14445 => 30105, 14446 => 21106, 14447 => 38761, 14448 => 33883, 14449 => 26684, + 14450 => 34532, 14451 => 38401, 14452 => 38548, 14453 => 38124, 14454 => 20010, + 14455 => 21508, 14456 => 32473, 14457 => 26681, 14458 => 36319, 14459 => 32789, + 14460 => 26356, 14461 => 24218, 14462 => 32697, 14625 => 22466, 14626 => 32831, + 14627 => 26775, 14628 => 24037, 14629 => 25915, 14630 => 21151, 14631 => 24685, + 14632 => 40858, 14633 => 20379, 14634 => 36524, 14635 => 20844, 14636 => 23467, + 14637 => 24339, 14638 => 24041, 14639 => 27742, 14640 => 25329, 14641 => 36129, + 14642 => 20849, 14643 => 38057, 14644 => 21246, 14645 => 27807, 14646 => 33503, + 14647 => 29399, 14648 => 22434, 14649 => 26500, 14650 => 36141, 14651 => 22815, + 14652 => 36764, 14653 => 33735, 14654 => 21653, 14655 => 31629, 14656 => 20272, + 14657 => 27837, 14658 => 23396, 14659 => 22993, 14660 => 40723, 14661 => 21476, + 14662 => 34506, 14663 => 39592, 14664 => 35895, 14665 => 32929, 14666 => 25925, + 14667 => 39038, 14668 => 22266, 14669 => 38599, 14670 => 21038, 14671 => 29916, + 14672 => 21072, 14673 => 23521, 14674 => 25346, 14675 => 35074, 14676 => 20054, + 14677 => 25296, 14678 => 24618, 14679 => 26874, 14680 => 20851, 14681 => 23448, + 14682 => 20896, 14683 => 35266, 14684 => 31649, 14685 => 39302, 14686 => 32592, + 14687 => 24815, 14688 => 28748, 14689 => 36143, 14690 => 20809, 14691 => 24191, + 14692 => 36891, 14693 => 29808, 14694 => 35268, 14695 => 22317, 14696 => 30789, + 14697 => 24402, 14698 => 40863, 14699 => 38394, 14700 => 36712, 14701 => 39740, + 14702 => 35809, 14703 => 30328, 14704 => 26690, 14705 => 26588, 14706 => 36330, + 14707 => 36149, 14708 => 21053, 14709 => 36746, 14710 => 28378, 14711 => 26829, + 14712 => 38149, 14713 => 37101, 14714 => 22269, 14715 => 26524, 14716 => 35065, + 14717 => 36807, 14718 => 21704, 14881 => 39608, 14882 => 23401, 14883 => 28023, + 14884 => 27686, 14885 => 20133, 14886 => 23475, 14887 => 39559, 14888 => 37219, + 14889 => 25000, 14890 => 37039, 14891 => 38889, 14892 => 21547, 14893 => 28085, + 14894 => 23506, 14895 => 20989, 14896 => 21898, 14897 => 32597, 14898 => 32752, + 14899 => 25788, 14900 => 25421, 14901 => 26097, 14902 => 25022, 14903 => 24717, + 14904 => 28938, 14905 => 27735, 14906 => 27721, 14907 => 22831, 14908 => 26477, + 14909 => 33322, 14910 => 22741, 14911 => 22158, 14912 => 35946, 14913 => 27627, + 14914 => 37085, 14915 => 22909, 14916 => 32791, 14917 => 21495, 14918 => 28009, + 14919 => 21621, 14920 => 21917, 14921 => 33655, 14922 => 33743, 14923 => 26680, + 14924 => 31166, 14925 => 21644, 14926 => 20309, 14927 => 21512, 14928 => 30418, + 14929 => 35977, 14930 => 38402, 14931 => 27827, 14932 => 28088, 14933 => 36203, + 14934 => 35088, 14935 => 40548, 14936 => 36154, 14937 => 22079, 14938 => 40657, + 14939 => 30165, 14940 => 24456, 14941 => 29408, 14942 => 24680, 14943 => 21756, + 14944 => 20136, 14945 => 27178, 14946 => 34913, 14947 => 24658, 14948 => 36720, + 14949 => 21700, 14950 => 28888, 14951 => 34425, 14952 => 40511, 14953 => 27946, + 14954 => 23439, 14955 => 24344, 14956 => 32418, 14957 => 21897, 14958 => 20399, + 14959 => 29492, 14960 => 21564, 14961 => 21402, 14962 => 20505, 14963 => 21518, + 14964 => 21628, 14965 => 20046, 14966 => 24573, 14967 => 29786, 14968 => 22774, + 14969 => 33899, 14970 => 32993, 14971 => 34676, 14972 => 29392, 14973 => 31946, + 14974 => 28246, 15137 => 24359, 15138 => 34382, 15139 => 21804, 15140 => 25252, + 15141 => 20114, 15142 => 27818, 15143 => 25143, 15144 => 33457, 15145 => 21719, + 15146 => 21326, 15147 => 29502, 15148 => 28369, 15149 => 30011, 15150 => 21010, + 15151 => 21270, 15152 => 35805, 15153 => 27088, 15154 => 24458, 15155 => 24576, + 15156 => 28142, 15157 => 22351, 15158 => 27426, 15159 => 29615, 15160 => 26707, + 15161 => 36824, 15162 => 32531, 15163 => 25442, 15164 => 24739, 15165 => 21796, + 15166 => 30186, 15167 => 35938, 15168 => 28949, 15169 => 28067, 15170 => 23462, + 15171 => 24187, 15172 => 33618, 15173 => 24908, 15174 => 40644, 15175 => 30970, + 15176 => 34647, 15177 => 31783, 15178 => 30343, 15179 => 20976, 15180 => 24822, + 15181 => 29004, 15182 => 26179, 15183 => 24140, 15184 => 24653, 15185 => 35854, + 15186 => 28784, 15187 => 25381, 15188 => 36745, 15189 => 24509, 15190 => 24674, + 15191 => 34516, 15192 => 22238, 15193 => 27585, 15194 => 24724, 15195 => 24935, + 15196 => 21321, 15197 => 24800, 15198 => 26214, 15199 => 36159, 15200 => 31229, + 15201 => 20250, 15202 => 28905, 15203 => 27719, 15204 => 35763, 15205 => 35826, + 15206 => 32472, 15207 => 33636, 15208 => 26127, 15209 => 23130, 15210 => 39746, + 15211 => 27985, 15212 => 28151, 15213 => 35905, 15214 => 27963, 15215 => 20249, + 15216 => 28779, 15217 => 33719, 15218 => 25110, 15219 => 24785, 15220 => 38669, + 15221 => 36135, 15222 => 31096, 15223 => 20987, 15224 => 22334, 15225 => 22522, + 15226 => 26426, 15227 => 30072, 15228 => 31293, 15229 => 31215, 15230 => 31637, + 15393 => 32908, 15394 => 39269, 15395 => 36857, 15396 => 28608, 15397 => 35749, + 15398 => 40481, 15399 => 23020, 15400 => 32489, 15401 => 32521, 15402 => 21513, + 15403 => 26497, 15404 => 26840, 15405 => 36753, 15406 => 31821, 15407 => 38598, + 15408 => 21450, 15409 => 24613, 15410 => 30142, 15411 => 27762, 15412 => 21363, + 15413 => 23241, 15414 => 32423, 15415 => 25380, 15416 => 20960, 15417 => 33034, + 15418 => 24049, 15419 => 34015, 15420 => 25216, 15421 => 20864, 15422 => 23395, + 15423 => 20238, 15424 => 31085, 15425 => 21058, 15426 => 24760, 15427 => 27982, + 15428 => 23492, 15429 => 23490, 15430 => 35745, 15431 => 35760, 15432 => 26082, + 15433 => 24524, 15434 => 38469, 15435 => 22931, 15436 => 32487, 15437 => 32426, + 15438 => 22025, 15439 => 26551, 15440 => 22841, 15441 => 20339, 15442 => 23478, + 15443 => 21152, 15444 => 33626, 15445 => 39050, 15446 => 36158, 15447 => 30002, + 15448 => 38078, 15449 => 20551, 15450 => 31292, 15451 => 20215, 15452 => 26550, + 15453 => 39550, 15454 => 23233, 15455 => 27516, 15456 => 30417, 15457 => 22362, + 15458 => 23574, 15459 => 31546, 15460 => 38388, 15461 => 29006, 15462 => 20860, + 15463 => 32937, 15464 => 33392, 15465 => 22904, 15466 => 32516, 15467 => 33575, + 15468 => 26816, 15469 => 26604, 15470 => 30897, 15471 => 30839, 15472 => 25315, + 15473 => 25441, 15474 => 31616, 15475 => 20461, 15476 => 21098, 15477 => 20943, + 15478 => 33616, 15479 => 27099, 15480 => 37492, 15481 => 36341, 15482 => 36145, + 15483 => 35265, 15484 => 38190, 15485 => 31661, 15486 => 20214, 15649 => 20581, + 15650 => 33328, 15651 => 21073, 15652 => 39279, 15653 => 28176, 15654 => 28293, + 15655 => 28071, 15656 => 24314, 15657 => 20725, 15658 => 23004, 15659 => 23558, + 15660 => 27974, 15661 => 27743, 15662 => 30086, 15663 => 33931, 15664 => 26728, + 15665 => 22870, 15666 => 35762, 15667 => 21280, 15668 => 37233, 15669 => 38477, + 15670 => 34121, 15671 => 26898, 15672 => 30977, 15673 => 28966, 15674 => 33014, + 15675 => 20132, 15676 => 37066, 15677 => 27975, 15678 => 39556, 15679 => 23047, + 15680 => 22204, 15681 => 25605, 15682 => 38128, 15683 => 30699, 15684 => 20389, + 15685 => 33050, 15686 => 29409, 15687 => 35282, 15688 => 39290, 15689 => 32564, + 15690 => 32478, 15691 => 21119, 15692 => 25945, 15693 => 37237, 15694 => 36735, + 15695 => 36739, 15696 => 21483, 15697 => 31382, 15698 => 25581, 15699 => 25509, + 15700 => 30342, 15701 => 31224, 15702 => 34903, 15703 => 38454, 15704 => 25130, + 15705 => 21163, 15706 => 33410, 15707 => 26708, 15708 => 26480, 15709 => 25463, + 15710 => 30571, 15711 => 31469, 15712 => 27905, 15713 => 32467, 15714 => 35299, + 15715 => 22992, 15716 => 25106, 15717 => 34249, 15718 => 33445, 15719 => 30028, + 15720 => 20511, 15721 => 20171, 15722 => 30117, 15723 => 35819, 15724 => 23626, + 15725 => 24062, 15726 => 31563, 15727 => 26020, 15728 => 37329, 15729 => 20170, + 15730 => 27941, 15731 => 35167, 15732 => 32039, 15733 => 38182, 15734 => 20165, + 15735 => 35880, 15736 => 36827, 15737 => 38771, 15738 => 26187, 15739 => 31105, + 15740 => 36817, 15741 => 28908, 15742 => 28024, 15905 => 23613, 15906 => 21170, + 15907 => 33606, 15908 => 20834, 15909 => 33550, 15910 => 30555, 15911 => 26230, + 15912 => 40120, 15913 => 20140, 15914 => 24778, 15915 => 31934, 15916 => 31923, + 15917 => 32463, 15918 => 20117, 15919 => 35686, 15920 => 26223, 15921 => 39048, + 15922 => 38745, 15923 => 22659, 15924 => 25964, 15925 => 38236, 15926 => 24452, + 15927 => 30153, 15928 => 38742, 15929 => 31455, 15930 => 31454, 15931 => 20928, + 15932 => 28847, 15933 => 31384, 15934 => 25578, 15935 => 31350, 15936 => 32416, + 15937 => 29590, 15938 => 38893, 15939 => 20037, 15940 => 28792, 15941 => 20061, + 15942 => 37202, 15943 => 21417, 15944 => 25937, 15945 => 26087, 15946 => 33276, + 15947 => 33285, 15948 => 21646, 15949 => 23601, 15950 => 30106, 15951 => 38816, + 15952 => 25304, 15953 => 29401, 15954 => 30141, 15955 => 23621, 15956 => 39545, + 15957 => 33738, 15958 => 23616, 15959 => 21632, 15960 => 30697, 15961 => 20030, + 15962 => 27822, 15963 => 32858, 15964 => 25298, 15965 => 25454, 15966 => 24040, + 15967 => 20855, 15968 => 36317, 15969 => 36382, 15970 => 38191, 15971 => 20465, + 15972 => 21477, 15973 => 24807, 15974 => 28844, 15975 => 21095, 15976 => 25424, + 15977 => 40515, 15978 => 23071, 15979 => 20518, 15980 => 30519, 15981 => 21367, + 15982 => 32482, 15983 => 25733, 15984 => 25899, 15985 => 25225, 15986 => 25496, + 15987 => 20500, 15988 => 29237, 15989 => 35273, 15990 => 20915, 15991 => 35776, + 15992 => 32477, 15993 => 22343, 15994 => 33740, 15995 => 38055, 15996 => 20891, + 15997 => 21531, 15998 => 23803, 16161 => 20426, 16162 => 31459, 16163 => 27994, + 16164 => 37089, 16165 => 39567, 16166 => 21888, 16167 => 21654, 16168 => 21345, + 16169 => 21679, 16170 => 24320, 16171 => 25577, 16172 => 26999, 16173 => 20975, + 16174 => 24936, 16175 => 21002, 16176 => 22570, 16177 => 21208, 16178 => 22350, + 16179 => 30733, 16180 => 30475, 16181 => 24247, 16182 => 24951, 16183 => 31968, + 16184 => 25179, 16185 => 25239, 16186 => 20130, 16187 => 28821, 16188 => 32771, + 16189 => 25335, 16190 => 28900, 16191 => 38752, 16192 => 22391, 16193 => 33499, + 16194 => 26607, 16195 => 26869, 16196 => 30933, 16197 => 39063, 16198 => 31185, + 16199 => 22771, 16200 => 21683, 16201 => 21487, 16202 => 28212, 16203 => 20811, + 16204 => 21051, 16205 => 23458, 16206 => 35838, 16207 => 32943, 16208 => 21827, + 16209 => 22438, 16210 => 24691, 16211 => 22353, 16212 => 21549, 16213 => 31354, + 16214 => 24656, 16215 => 23380, 16216 => 25511, 16217 => 25248, 16218 => 21475, + 16219 => 25187, 16220 => 23495, 16221 => 26543, 16222 => 21741, 16223 => 31391, + 16224 => 33510, 16225 => 37239, 16226 => 24211, 16227 => 35044, 16228 => 22840, + 16229 => 22446, 16230 => 25358, 16231 => 36328, 16232 => 33007, 16233 => 22359, + 16234 => 31607, 16235 => 20393, 16236 => 24555, 16237 => 23485, 16238 => 27454, + 16239 => 21281, 16240 => 31568, 16241 => 29378, 16242 => 26694, 16243 => 30719, + 16244 => 30518, 16245 => 26103, 16246 => 20917, 16247 => 20111, 16248 => 30420, + 16249 => 23743, 16250 => 31397, 16251 => 33909, 16252 => 22862, 16253 => 39745, + 16254 => 20608, 16417 => 39304, 16418 => 24871, 16419 => 28291, 16420 => 22372, + 16421 => 26118, 16422 => 25414, 16423 => 22256, 16424 => 25324, 16425 => 25193, + 16426 => 24275, 16427 => 38420, 16428 => 22403, 16429 => 25289, 16430 => 21895, + 16431 => 34593, 16432 => 33098, 16433 => 36771, 16434 => 21862, 16435 => 33713, + 16436 => 26469, 16437 => 36182, 16438 => 34013, 16439 => 23146, 16440 => 26639, + 16441 => 25318, 16442 => 31726, 16443 => 38417, 16444 => 20848, 16445 => 28572, + 16446 => 35888, 16447 => 25597, 16448 => 35272, 16449 => 25042, 16450 => 32518, + 16451 => 28866, 16452 => 28389, 16453 => 29701, 16454 => 27028, 16455 => 29436, + 16456 => 24266, 16457 => 37070, 16458 => 26391, 16459 => 28010, 16460 => 25438, + 16461 => 21171, 16462 => 29282, 16463 => 32769, 16464 => 20332, 16465 => 23013, + 16466 => 37226, 16467 => 28889, 16468 => 28061, 16469 => 21202, 16470 => 20048, + 16471 => 38647, 16472 => 38253, 16473 => 34174, 16474 => 30922, 16475 => 32047, + 16476 => 20769, 16477 => 22418, 16478 => 25794, 16479 => 32907, 16480 => 31867, + 16481 => 27882, 16482 => 26865, 16483 => 26974, 16484 => 20919, 16485 => 21400, + 16486 => 26792, 16487 => 29313, 16488 => 40654, 16489 => 31729, 16490 => 29432, + 16491 => 31163, 16492 => 28435, 16493 => 29702, 16494 => 26446, 16495 => 37324, + 16496 => 40100, 16497 => 31036, 16498 => 33673, 16499 => 33620, 16500 => 21519, + 16501 => 26647, 16502 => 20029, 16503 => 21385, 16504 => 21169, 16505 => 30782, + 16506 => 21382, 16507 => 21033, 16508 => 20616, 16509 => 20363, 16510 => 20432, + 16673 => 30178, 16674 => 31435, 16675 => 31890, 16676 => 27813, 16677 => 38582, + 16678 => 21147, 16679 => 29827, 16680 => 21737, 16681 => 20457, 16682 => 32852, + 16683 => 33714, 16684 => 36830, 16685 => 38256, 16686 => 24265, 16687 => 24604, + 16688 => 28063, 16689 => 24088, 16690 => 25947, 16691 => 33080, 16692 => 38142, + 16693 => 24651, 16694 => 28860, 16695 => 32451, 16696 => 31918, 16697 => 20937, + 16698 => 26753, 16699 => 31921, 16700 => 33391, 16701 => 20004, 16702 => 36742, + 16703 => 37327, 16704 => 26238, 16705 => 20142, 16706 => 35845, 16707 => 25769, + 16708 => 32842, 16709 => 20698, 16710 => 30103, 16711 => 29134, 16712 => 23525, + 16713 => 36797, 16714 => 28518, 16715 => 20102, 16716 => 25730, 16717 => 38243, + 16718 => 24278, 16719 => 26009, 16720 => 21015, 16721 => 35010, 16722 => 28872, + 16723 => 21155, 16724 => 29454, 16725 => 29747, 16726 => 26519, 16727 => 30967, + 16728 => 38678, 16729 => 20020, 16730 => 37051, 16731 => 40158, 16732 => 28107, + 16733 => 20955, 16734 => 36161, 16735 => 21533, 16736 => 25294, 16737 => 29618, + 16738 => 33777, 16739 => 38646, 16740 => 40836, 16741 => 38083, 16742 => 20278, + 16743 => 32666, 16744 => 20940, 16745 => 28789, 16746 => 38517, 16747 => 23725, + 16748 => 39046, 16749 => 21478, 16750 => 20196, 16751 => 28316, 16752 => 29705, + 16753 => 27060, 16754 => 30827, 16755 => 39311, 16756 => 30041, 16757 => 21016, + 16758 => 30244, 16759 => 27969, 16760 => 26611, 16761 => 20845, 16762 => 40857, + 16763 => 32843, 16764 => 21657, 16765 => 31548, 16766 => 31423, 16929 => 38534, + 16930 => 22404, 16931 => 25314, 16932 => 38471, 16933 => 27004, 16934 => 23044, + 16935 => 25602, 16936 => 31699, 16937 => 28431, 16938 => 38475, 16939 => 33446, + 16940 => 21346, 16941 => 39045, 16942 => 24208, 16943 => 28809, 16944 => 25523, + 16945 => 21348, 16946 => 34383, 16947 => 40065, 16948 => 40595, 16949 => 30860, + 16950 => 38706, 16951 => 36335, 16952 => 36162, 16953 => 40575, 16954 => 28510, + 16955 => 31108, 16956 => 24405, 16957 => 38470, 16958 => 25134, 16959 => 39540, + 16960 => 21525, 16961 => 38109, 16962 => 20387, 16963 => 26053, 16964 => 23653, + 16965 => 23649, 16966 => 32533, 16967 => 34385, 16968 => 27695, 16969 => 24459, + 16970 => 29575, 16971 => 28388, 16972 => 32511, 16973 => 23782, 16974 => 25371, + 16975 => 23402, 16976 => 28390, 16977 => 21365, 16978 => 20081, 16979 => 25504, + 16980 => 30053, 16981 => 25249, 16982 => 36718, 16983 => 20262, 16984 => 20177, + 16985 => 27814, 16986 => 32438, 16987 => 35770, 16988 => 33821, 16989 => 34746, + 16990 => 32599, 16991 => 36923, 16992 => 38179, 16993 => 31657, 16994 => 39585, + 16995 => 35064, 16996 => 33853, 16997 => 27931, 16998 => 39558, 16999 => 32476, + 17000 => 22920, 17001 => 40635, 17002 => 29595, 17003 => 30721, 17004 => 34434, + 17005 => 39532, 17006 => 39554, 17007 => 22043, 17008 => 21527, 17009 => 22475, + 17010 => 20080, 17011 => 40614, 17012 => 21334, 17013 => 36808, 17014 => 33033, + 17015 => 30610, 17016 => 39314, 17017 => 34542, 17018 => 28385, 17019 => 34067, + 17020 => 26364, 17021 => 24930, 17022 => 28459, 17185 => 35881, 17186 => 33426, + 17187 => 33579, 17188 => 30450, 17189 => 27667, 17190 => 24537, 17191 => 33725, + 17192 => 29483, 17193 => 33541, 17194 => 38170, 17195 => 27611, 17196 => 30683, + 17197 => 38086, 17198 => 21359, 17199 => 33538, 17200 => 20882, 17201 => 24125, + 17202 => 35980, 17203 => 36152, 17204 => 20040, 17205 => 29611, 17206 => 26522, + 17207 => 26757, 17208 => 37238, 17209 => 38665, 17210 => 29028, 17211 => 27809, + 17212 => 30473, 17213 => 23186, 17214 => 38209, 17215 => 27599, 17216 => 32654, + 17217 => 26151, 17218 => 23504, 17219 => 22969, 17220 => 23194, 17221 => 38376, + 17222 => 38391, 17223 => 20204, 17224 => 33804, 17225 => 33945, 17226 => 27308, + 17227 => 30431, 17228 => 38192, 17229 => 29467, 17230 => 26790, 17231 => 23391, + 17232 => 30511, 17233 => 37274, 17234 => 38753, 17235 => 31964, 17236 => 36855, + 17237 => 35868, 17238 => 24357, 17239 => 31859, 17240 => 31192, 17241 => 35269, + 17242 => 27852, 17243 => 34588, 17244 => 23494, 17245 => 24130, 17246 => 26825, + 17247 => 30496, 17248 => 32501, 17249 => 20885, 17250 => 20813, 17251 => 21193, + 17252 => 23081, 17253 => 32517, 17254 => 38754, 17255 => 33495, 17256 => 25551, + 17257 => 30596, 17258 => 34256, 17259 => 31186, 17260 => 28218, 17261 => 24217, + 17262 => 22937, 17263 => 34065, 17264 => 28781, 17265 => 27665, 17266 => 25279, + 17267 => 30399, 17268 => 25935, 17269 => 24751, 17270 => 38397, 17271 => 26126, + 17272 => 34719, 17273 => 40483, 17274 => 38125, 17275 => 21517, 17276 => 21629, + 17277 => 35884, 17278 => 25720, 17441 => 25721, 17442 => 34321, 17443 => 27169, + 17444 => 33180, 17445 => 30952, 17446 => 25705, 17447 => 39764, 17448 => 25273, + 17449 => 26411, 17450 => 33707, 17451 => 22696, 17452 => 40664, 17453 => 27819, + 17454 => 28448, 17455 => 23518, 17456 => 38476, 17457 => 35851, 17458 => 29279, + 17459 => 26576, 17460 => 25287, 17461 => 29281, 17462 => 20137, 17463 => 22982, + 17464 => 27597, 17465 => 22675, 17466 => 26286, 17467 => 24149, 17468 => 21215, + 17469 => 24917, 17470 => 26408, 17471 => 30446, 17472 => 30566, 17473 => 29287, + 17474 => 31302, 17475 => 25343, 17476 => 21738, 17477 => 21584, 17478 => 38048, + 17479 => 37027, 17480 => 23068, 17481 => 32435, 17482 => 27670, 17483 => 20035, + 17484 => 22902, 17485 => 32784, 17486 => 22856, 17487 => 21335, 17488 => 30007, + 17489 => 38590, 17490 => 22218, 17491 => 25376, 17492 => 33041, 17493 => 24700, + 17494 => 38393, 17495 => 28118, 17496 => 21602, 17497 => 39297, 17498 => 20869, + 17499 => 23273, 17500 => 33021, 17501 => 22958, 17502 => 38675, 17503 => 20522, + 17504 => 27877, 17505 => 23612, 17506 => 25311, 17507 => 20320, 17508 => 21311, + 17509 => 33147, 17510 => 36870, 17511 => 28346, 17512 => 34091, 17513 => 25288, + 17514 => 24180, 17515 => 30910, 17516 => 25781, 17517 => 25467, 17518 => 24565, + 17519 => 23064, 17520 => 37247, 17521 => 40479, 17522 => 23615, 17523 => 25423, + 17524 => 32834, 17525 => 23421, 17526 => 21870, 17527 => 38218, 17528 => 38221, + 17529 => 28037, 17530 => 24744, 17531 => 26592, 17532 => 29406, 17533 => 20957, + 17534 => 23425, 17697 => 25319, 17698 => 27870, 17699 => 29275, 17700 => 25197, + 17701 => 38062, 17702 => 32445, 17703 => 33043, 17704 => 27987, 17705 => 20892, + 17706 => 24324, 17707 => 22900, 17708 => 21162, 17709 => 24594, 17710 => 22899, + 17711 => 26262, 17712 => 34384, 17713 => 30111, 17714 => 25386, 17715 => 25062, + 17716 => 31983, 17717 => 35834, 17718 => 21734, 17719 => 27431, 17720 => 40485, + 17721 => 27572, 17722 => 34261, 17723 => 21589, 17724 => 20598, 17725 => 27812, + 17726 => 21866, 17727 => 36276, 17728 => 29228, 17729 => 24085, 17730 => 24597, + 17731 => 29750, 17732 => 25293, 17733 => 25490, 17734 => 29260, 17735 => 24472, + 17736 => 28227, 17737 => 27966, 17738 => 25856, 17739 => 28504, 17740 => 30424, + 17741 => 30928, 17742 => 30460, 17743 => 30036, 17744 => 21028, 17745 => 21467, + 17746 => 20051, 17747 => 24222, 17748 => 26049, 17749 => 32810, 17750 => 32982, + 17751 => 25243, 17752 => 21638, 17753 => 21032, 17754 => 28846, 17755 => 34957, + 17756 => 36305, 17757 => 27873, 17758 => 21624, 17759 => 32986, 17760 => 22521, + 17761 => 35060, 17762 => 36180, 17763 => 38506, 17764 => 37197, 17765 => 20329, + 17766 => 27803, 17767 => 21943, 17768 => 30406, 17769 => 30768, 17770 => 25256, + 17771 => 28921, 17772 => 28558, 17773 => 24429, 17774 => 34028, 17775 => 26842, + 17776 => 30844, 17777 => 31735, 17778 => 33192, 17779 => 26379, 17780 => 40527, + 17781 => 25447, 17782 => 30896, 17783 => 22383, 17784 => 30738, 17785 => 38713, + 17786 => 25209, 17787 => 25259, 17788 => 21128, 17789 => 29749, 17790 => 27607, + 17953 => 21860, 17954 => 33086, 17955 => 30130, 17956 => 30382, 17957 => 21305, + 17958 => 30174, 17959 => 20731, 17960 => 23617, 17961 => 35692, 17962 => 31687, + 17963 => 20559, 17964 => 29255, 17965 => 39575, 17966 => 39128, 17967 => 28418, + 17968 => 29922, 17969 => 31080, 17970 => 25735, 17971 => 30629, 17972 => 25340, + 17973 => 39057, 17974 => 36139, 17975 => 21697, 17976 => 32856, 17977 => 20050, + 17978 => 22378, 17979 => 33529, 17980 => 33805, 17981 => 24179, 17982 => 20973, + 17983 => 29942, 17984 => 35780, 17985 => 23631, 17986 => 22369, 17987 => 27900, + 17988 => 39047, 17989 => 23110, 17990 => 30772, 17991 => 39748, 17992 => 36843, + 17993 => 31893, 17994 => 21078, 17995 => 25169, 17996 => 38138, 17997 => 20166, + 17998 => 33670, 17999 => 33889, 18000 => 33769, 18001 => 33970, 18002 => 22484, + 18003 => 26420, 18004 => 22275, 18005 => 26222, 18006 => 28006, 18007 => 35889, + 18008 => 26333, 18009 => 28689, 18010 => 26399, 18011 => 27450, 18012 => 26646, + 18013 => 25114, 18014 => 22971, 18015 => 19971, 18016 => 20932, 18017 => 28422, + 18018 => 26578, 18019 => 27791, 18020 => 20854, 18021 => 26827, 18022 => 22855, + 18023 => 27495, 18024 => 30054, 18025 => 23822, 18026 => 33040, 18027 => 40784, + 18028 => 26071, 18029 => 31048, 18030 => 31041, 18031 => 39569, 18032 => 36215, + 18033 => 23682, 18034 => 20062, 18035 => 20225, 18036 => 21551, 18037 => 22865, + 18038 => 30732, 18039 => 22120, 18040 => 27668, 18041 => 36804, 18042 => 24323, + 18043 => 27773, 18044 => 27875, 18045 => 35755, 18046 => 25488, 18209 => 24688, + 18210 => 27965, 18211 => 29301, 18212 => 25190, 18213 => 38030, 18214 => 38085, + 18215 => 21315, 18216 => 36801, 18217 => 31614, 18218 => 20191, 18219 => 35878, + 18220 => 20094, 18221 => 40660, 18222 => 38065, 18223 => 38067, 18224 => 21069, + 18225 => 28508, 18226 => 36963, 18227 => 27973, 18228 => 35892, 18229 => 22545, + 18230 => 23884, 18231 => 27424, 18232 => 27465, 18233 => 26538, 18234 => 21595, + 18235 => 33108, 18236 => 32652, 18237 => 22681, 18238 => 34103, 18239 => 24378, + 18240 => 25250, 18241 => 27207, 18242 => 38201, 18243 => 25970, 18244 => 24708, + 18245 => 26725, 18246 => 30631, 18247 => 20052, 18248 => 20392, 18249 => 24039, + 18250 => 38808, 18251 => 25772, 18252 => 32728, 18253 => 23789, 18254 => 20431, + 18255 => 31373, 18256 => 20999, 18257 => 33540, 18258 => 19988, 18259 => 24623, + 18260 => 31363, 18261 => 38054, 18262 => 20405, 18263 => 20146, 18264 => 31206, + 18265 => 29748, 18266 => 21220, 18267 => 33465, 18268 => 25810, 18269 => 31165, + 18270 => 23517, 18271 => 27777, 18272 => 38738, 18273 => 36731, 18274 => 27682, + 18275 => 20542, 18276 => 21375, 18277 => 28165, 18278 => 25806, 18279 => 26228, + 18280 => 27696, 18281 => 24773, 18282 => 39031, 18283 => 35831, 18284 => 24198, + 18285 => 29756, 18286 => 31351, 18287 => 31179, 18288 => 19992, 18289 => 37041, + 18290 => 29699, 18291 => 27714, 18292 => 22234, 18293 => 37195, 18294 => 27845, + 18295 => 36235, 18296 => 21306, 18297 => 34502, 18298 => 26354, 18299 => 36527, + 18300 => 23624, 18301 => 39537, 18302 => 28192, 18465 => 21462, 18466 => 23094, + 18467 => 40843, 18468 => 36259, 18469 => 21435, 18470 => 22280, 18471 => 39079, + 18472 => 26435, 18473 => 37275, 18474 => 27849, 18475 => 20840, 18476 => 30154, + 18477 => 25331, 18478 => 29356, 18479 => 21048, 18480 => 21149, 18481 => 32570, + 18482 => 28820, 18483 => 30264, 18484 => 21364, 18485 => 40522, 18486 => 27063, + 18487 => 30830, 18488 => 38592, 18489 => 35033, 18490 => 32676, 18491 => 28982, + 18492 => 29123, 18493 => 20873, 18494 => 26579, 18495 => 29924, 18496 => 22756, + 18497 => 25880, 18498 => 22199, 18499 => 35753, 18500 => 39286, 18501 => 25200, + 18502 => 32469, 18503 => 24825, 18504 => 28909, 18505 => 22764, 18506 => 20161, + 18507 => 20154, 18508 => 24525, 18509 => 38887, 18510 => 20219, 18511 => 35748, + 18512 => 20995, 18513 => 22922, 18514 => 32427, 18515 => 25172, 18516 => 20173, + 18517 => 26085, 18518 => 25102, 18519 => 33592, 18520 => 33993, 18521 => 33635, + 18522 => 34701, 18523 => 29076, 18524 => 28342, 18525 => 23481, 18526 => 32466, + 18527 => 20887, 18528 => 25545, 18529 => 26580, 18530 => 32905, 18531 => 33593, + 18532 => 34837, 18533 => 20754, 18534 => 23418, 18535 => 22914, 18536 => 36785, + 18537 => 20083, 18538 => 27741, 18539 => 20837, 18540 => 35109, 18541 => 36719, + 18542 => 38446, 18543 => 34122, 18544 => 29790, 18545 => 38160, 18546 => 38384, + 18547 => 28070, 18548 => 33509, 18549 => 24369, 18550 => 25746, 18551 => 27922, + 18552 => 33832, 18553 => 33134, 18554 => 40131, 18555 => 22622, 18556 => 36187, + 18557 => 19977, 18558 => 21441, 18721 => 20254, 18722 => 25955, 18723 => 26705, + 18724 => 21971, 18725 => 20007, 18726 => 25620, 18727 => 39578, 18728 => 25195, + 18729 => 23234, 18730 => 29791, 18731 => 33394, 18732 => 28073, 18733 => 26862, + 18734 => 20711, 18735 => 33678, 18736 => 30722, 18737 => 26432, 18738 => 21049, + 18739 => 27801, 18740 => 32433, 18741 => 20667, 18742 => 21861, 18743 => 29022, + 18744 => 31579, 18745 => 26194, 18746 => 29642, 18747 => 33515, 18748 => 26441, + 18749 => 23665, 18750 => 21024, 18751 => 29053, 18752 => 34923, 18753 => 38378, + 18754 => 38485, 18755 => 25797, 18756 => 36193, 18757 => 33203, 18758 => 21892, + 18759 => 27733, 18760 => 25159, 18761 => 32558, 18762 => 22674, 18763 => 20260, + 18764 => 21830, 18765 => 36175, 18766 => 26188, 18767 => 19978, 18768 => 23578, + 18769 => 35059, 18770 => 26786, 18771 => 25422, 18772 => 31245, 18773 => 28903, + 18774 => 33421, 18775 => 21242, 18776 => 38902, 18777 => 23569, 18778 => 21736, + 18779 => 37045, 18780 => 32461, 18781 => 22882, 18782 => 36170, 18783 => 34503, + 18784 => 33292, 18785 => 33293, 18786 => 36198, 18787 => 25668, 18788 => 23556, + 18789 => 24913, 18790 => 28041, 18791 => 31038, 18792 => 35774, 18793 => 30775, + 18794 => 30003, 18795 => 21627, 18796 => 20280, 18797 => 36523, 18798 => 28145, + 18799 => 23072, 18800 => 32453, 18801 => 31070, 18802 => 27784, 18803 => 23457, + 18804 => 23158, 18805 => 29978, 18806 => 32958, 18807 => 24910, 18808 => 28183, + 18809 => 22768, 18810 => 29983, 18811 => 29989, 18812 => 29298, 18813 => 21319, + 18814 => 32499, 18977 => 30465, 18978 => 30427, 18979 => 21097, 18980 => 32988, + 18981 => 22307, 18982 => 24072, 18983 => 22833, 18984 => 29422, 18985 => 26045, + 18986 => 28287, 18987 => 35799, 18988 => 23608, 18989 => 34417, 18990 => 21313, + 18991 => 30707, 18992 => 25342, 18993 => 26102, 18994 => 20160, 18995 => 39135, + 18996 => 34432, 18997 => 23454, 18998 => 35782, 18999 => 21490, 19000 => 30690, + 19001 => 20351, 19002 => 23630, 19003 => 39542, 19004 => 22987, 19005 => 24335, + 19006 => 31034, 19007 => 22763, 19008 => 19990, 19009 => 26623, 19010 => 20107, + 19011 => 25325, 19012 => 35475, 19013 => 36893, 19014 => 21183, 19015 => 26159, + 19016 => 21980, 19017 => 22124, 19018 => 36866, 19019 => 20181, 19020 => 20365, + 19021 => 37322, 19022 => 39280, 19023 => 27663, 19024 => 24066, 19025 => 24643, + 19026 => 23460, 19027 => 35270, 19028 => 35797, 19029 => 25910, 19030 => 25163, + 19031 => 39318, 19032 => 23432, 19033 => 23551, 19034 => 25480, 19035 => 21806, + 19036 => 21463, 19037 => 30246, 19038 => 20861, 19039 => 34092, 19040 => 26530, + 19041 => 26803, 19042 => 27530, 19043 => 25234, 19044 => 36755, 19045 => 21460, + 19046 => 33298, 19047 => 28113, 19048 => 30095, 19049 => 20070, 19050 => 36174, + 19051 => 23408, 19052 => 29087, 19053 => 34223, 19054 => 26257, 19055 => 26329, + 19056 => 32626, 19057 => 34560, 19058 => 40653, 19059 => 40736, 19060 => 23646, + 19061 => 26415, 19062 => 36848, 19063 => 26641, 19064 => 26463, 19065 => 25101, + 19066 => 31446, 19067 => 22661, 19068 => 24246, 19069 => 25968, 19070 => 28465, + 19233 => 24661, 19234 => 21047, 19235 => 32781, 19236 => 25684, 19237 => 34928, + 19238 => 29993, 19239 => 24069, 19240 => 26643, 19241 => 25332, 19242 => 38684, + 19243 => 21452, 19244 => 29245, 19245 => 35841, 19246 => 27700, 19247 => 30561, + 19248 => 31246, 19249 => 21550, 19250 => 30636, 19251 => 39034, 19252 => 33308, + 19253 => 35828, 19254 => 30805, 19255 => 26388, 19256 => 28865, 19257 => 26031, + 19258 => 25749, 19259 => 22070, 19260 => 24605, 19261 => 31169, 19262 => 21496, + 19263 => 19997, 19264 => 27515, 19265 => 32902, 19266 => 23546, 19267 => 21987, + 19268 => 22235, 19269 => 20282, 19270 => 20284, 19271 => 39282, 19272 => 24051, + 19273 => 26494, 19274 => 32824, 19275 => 24578, 19276 => 39042, 19277 => 36865, + 19278 => 23435, 19279 => 35772, 19280 => 35829, 19281 => 25628, 19282 => 33368, + 19283 => 25822, 19284 => 22013, 19285 => 33487, 19286 => 37221, 19287 => 20439, + 19288 => 32032, 19289 => 36895, 19290 => 31903, 19291 => 20723, 19292 => 22609, + 19293 => 28335, 19294 => 23487, 19295 => 35785, 19296 => 32899, 19297 => 37240, + 19298 => 33948, 19299 => 31639, 19300 => 34429, 19301 => 38539, 19302 => 38543, + 19303 => 32485, 19304 => 39635, 19305 => 30862, 19306 => 23681, 19307 => 31319, + 19308 => 36930, 19309 => 38567, 19310 => 31071, 19311 => 23385, 19312 => 25439, + 19313 => 31499, 19314 => 34001, 19315 => 26797, 19316 => 21766, 19317 => 32553, + 19318 => 29712, 19319 => 32034, 19320 => 38145, 19321 => 25152, 19322 => 22604, + 19323 => 20182, 19324 => 23427, 19325 => 22905, 19326 => 22612, 19489 => 29549, + 19490 => 25374, 19491 => 36427, 19492 => 36367, 19493 => 32974, 19494 => 33492, + 19495 => 25260, 19496 => 21488, 19497 => 27888, 19498 => 37214, 19499 => 22826, + 19500 => 24577, 19501 => 27760, 19502 => 22349, 19503 => 25674, 19504 => 36138, + 19505 => 30251, 19506 => 28393, 19507 => 22363, 19508 => 27264, 19509 => 30192, + 19510 => 28525, 19511 => 35885, 19512 => 35848, 19513 => 22374, 19514 => 27631, + 19515 => 34962, 19516 => 30899, 19517 => 25506, 19518 => 21497, 19519 => 28845, + 19520 => 27748, 19521 => 22616, 19522 => 25642, 19523 => 22530, 19524 => 26848, + 19525 => 33179, 19526 => 21776, 19527 => 31958, 19528 => 20504, 19529 => 36538, + 19530 => 28108, 19531 => 36255, 19532 => 28907, 19533 => 25487, 19534 => 28059, + 19535 => 28372, 19536 => 32486, 19537 => 33796, 19538 => 26691, 19539 => 36867, + 19540 => 28120, 19541 => 38518, 19542 => 35752, 19543 => 22871, 19544 => 29305, + 19545 => 34276, 19546 => 33150, 19547 => 30140, 19548 => 35466, 19549 => 26799, + 19550 => 21076, 19551 => 36386, 19552 => 38161, 19553 => 25552, 19554 => 39064, + 19555 => 36420, 19556 => 21884, 19557 => 20307, 19558 => 26367, 19559 => 22159, + 19560 => 24789, 19561 => 28053, 19562 => 21059, 19563 => 23625, 19564 => 22825, + 19565 => 28155, 19566 => 22635, 19567 => 30000, 19568 => 29980, 19569 => 24684, + 19570 => 33300, 19571 => 33094, 19572 => 25361, 19573 => 26465, 19574 => 36834, + 19575 => 30522, 19576 => 36339, 19577 => 36148, 19578 => 38081, 19579 => 24086, + 19580 => 21381, 19581 => 21548, 19582 => 28867, 19745 => 27712, 19746 => 24311, + 19747 => 20572, 19748 => 20141, 19749 => 24237, 19750 => 25402, 19751 => 33351, + 19752 => 36890, 19753 => 26704, 19754 => 37230, 19755 => 30643, 19756 => 21516, + 19757 => 38108, 19758 => 24420, 19759 => 31461, 19760 => 26742, 19761 => 25413, + 19762 => 31570, 19763 => 32479, 19764 => 30171, 19765 => 20599, 19766 => 25237, + 19767 => 22836, 19768 => 36879, 19769 => 20984, 19770 => 31171, 19771 => 31361, + 19772 => 22270, 19773 => 24466, 19774 => 36884, 19775 => 28034, 19776 => 23648, + 19777 => 22303, 19778 => 21520, 19779 => 20820, 19780 => 28237, 19781 => 22242, + 19782 => 25512, 19783 => 39059, 19784 => 33151, 19785 => 34581, 19786 => 35114, + 19787 => 36864, 19788 => 21534, 19789 => 23663, 19790 => 33216, 19791 => 25302, + 19792 => 25176, 19793 => 33073, 19794 => 40501, 19795 => 38464, 19796 => 39534, + 19797 => 39548, 19798 => 26925, 19799 => 22949, 19800 => 25299, 19801 => 21822, + 19802 => 25366, 19803 => 21703, 19804 => 34521, 19805 => 27964, 19806 => 23043, + 19807 => 29926, 19808 => 34972, 19809 => 27498, 19810 => 22806, 19811 => 35916, + 19812 => 24367, 19813 => 28286, 19814 => 29609, 19815 => 39037, 19816 => 20024, + 19817 => 28919, 19818 => 23436, 19819 => 30871, 19820 => 25405, 19821 => 26202, + 19822 => 30358, 19823 => 24779, 19824 => 23451, 19825 => 23113, 19826 => 19975, + 19827 => 33109, 19828 => 27754, 19829 => 29579, 19830 => 20129, 19831 => 26505, + 19832 => 32593, 19833 => 24448, 19834 => 26106, 19835 => 26395, 19836 => 24536, + 19837 => 22916, 19838 => 23041, 20001 => 24013, 20002 => 24494, 20003 => 21361, + 20004 => 38886, 20005 => 36829, 20006 => 26693, 20007 => 22260, 20008 => 21807, + 20009 => 24799, 20010 => 20026, 20011 => 28493, 20012 => 32500, 20013 => 33479, + 20014 => 33806, 20015 => 22996, 20016 => 20255, 20017 => 20266, 20018 => 23614, + 20019 => 32428, 20020 => 26410, 20021 => 34074, 20022 => 21619, 20023 => 30031, + 20024 => 32963, 20025 => 21890, 20026 => 39759, 20027 => 20301, 20028 => 28205, + 20029 => 35859, 20030 => 23561, 20031 => 24944, 20032 => 21355, 20033 => 30239, + 20034 => 28201, 20035 => 34442, 20036 => 25991, 20037 => 38395, 20038 => 32441, + 20039 => 21563, 20040 => 31283, 20041 => 32010, 20042 => 38382, 20043 => 21985, + 20044 => 32705, 20045 => 29934, 20046 => 25373, 20047 => 34583, 20048 => 28065, + 20049 => 31389, 20050 => 25105, 20051 => 26017, 20052 => 21351, 20053 => 25569, + 20054 => 27779, 20055 => 24043, 20056 => 21596, 20057 => 38056, 20058 => 20044, + 20059 => 27745, 20060 => 35820, 20061 => 23627, 20062 => 26080, 20063 => 33436, + 20064 => 26791, 20065 => 21566, 20066 => 21556, 20067 => 27595, 20068 => 27494, + 20069 => 20116, 20070 => 25410, 20071 => 21320, 20072 => 33310, 20073 => 20237, + 20074 => 20398, 20075 => 22366, 20076 => 25098, 20077 => 38654, 20078 => 26212, + 20079 => 29289, 20080 => 21247, 20081 => 21153, 20082 => 24735, 20083 => 35823, + 20084 => 26132, 20085 => 29081, 20086 => 26512, 20087 => 35199, 20088 => 30802, + 20089 => 30717, 20090 => 26224, 20091 => 22075, 20092 => 21560, 20093 => 38177, + 20094 => 29306, 20257 => 31232, 20258 => 24687, 20259 => 24076, 20260 => 24713, + 20261 => 33181, 20262 => 22805, 20263 => 24796, 20264 => 29060, 20265 => 28911, + 20266 => 28330, 20267 => 27728, 20268 => 29312, 20269 => 27268, 20270 => 34989, + 20271 => 24109, 20272 => 20064, 20273 => 23219, 20274 => 21916, 20275 => 38115, + 20276 => 27927, 20277 => 31995, 20278 => 38553, 20279 => 25103, 20280 => 32454, + 20281 => 30606, 20282 => 34430, 20283 => 21283, 20284 => 38686, 20285 => 36758, + 20286 => 26247, 20287 => 23777, 20288 => 20384, 20289 => 29421, 20290 => 19979, + 20291 => 21414, 20292 => 22799, 20293 => 21523, 20294 => 25472, 20295 => 38184, + 20296 => 20808, 20297 => 20185, 20298 => 40092, 20299 => 32420, 20300 => 21688, + 20301 => 36132, 20302 => 34900, 20303 => 33335, 20304 => 38386, 20305 => 28046, + 20306 => 24358, 20307 => 23244, 20308 => 26174, 20309 => 38505, 20310 => 29616, + 20311 => 29486, 20312 => 21439, 20313 => 33146, 20314 => 39301, 20315 => 32673, + 20316 => 23466, 20317 => 38519, 20318 => 38480, 20319 => 32447, 20320 => 30456, + 20321 => 21410, 20322 => 38262, 20323 => 39321, 20324 => 31665, 20325 => 35140, + 20326 => 28248, 20327 => 20065, 20328 => 32724, 20329 => 31077, 20330 => 35814, + 20331 => 24819, 20332 => 21709, 20333 => 20139, 20334 => 39033, 20335 => 24055, + 20336 => 27233, 20337 => 20687, 20338 => 21521, 20339 => 35937, 20340 => 33831, + 20341 => 30813, 20342 => 38660, 20343 => 21066, 20344 => 21742, 20345 => 22179, + 20346 => 38144, 20347 => 28040, 20348 => 23477, 20349 => 28102, 20350 => 26195, + 20513 => 23567, 20514 => 23389, 20515 => 26657, 20516 => 32918, 20517 => 21880, + 20518 => 31505, 20519 => 25928, 20520 => 26964, 20521 => 20123, 20522 => 27463, + 20523 => 34638, 20524 => 38795, 20525 => 21327, 20526 => 25375, 20527 => 25658, + 20528 => 37034, 20529 => 26012, 20530 => 32961, 20531 => 35856, 20532 => 20889, + 20533 => 26800, 20534 => 21368, 20535 => 34809, 20536 => 25032, 20537 => 27844, + 20538 => 27899, 20539 => 35874, 20540 => 23633, 20541 => 34218, 20542 => 33455, + 20543 => 38156, 20544 => 27427, 20545 => 36763, 20546 => 26032, 20547 => 24571, + 20548 => 24515, 20549 => 20449, 20550 => 34885, 20551 => 26143, 20552 => 33125, + 20553 => 29481, 20554 => 24826, 20555 => 20852, 20556 => 21009, 20557 => 22411, + 20558 => 24418, 20559 => 37026, 20560 => 34892, 20561 => 37266, 20562 => 24184, + 20563 => 26447, 20564 => 24615, 20565 => 22995, 20566 => 20804, 20567 => 20982, + 20568 => 33016, 20569 => 21256, 20570 => 27769, 20571 => 38596, 20572 => 29066, + 20573 => 20241, 20574 => 20462, 20575 => 32670, 20576 => 26429, 20577 => 21957, + 20578 => 38152, 20579 => 31168, 20580 => 34966, 20581 => 32483, 20582 => 22687, + 20583 => 25100, 20584 => 38656, 20585 => 34394, 20586 => 22040, 20587 => 39035, + 20588 => 24464, 20589 => 35768, 20590 => 33988, 20591 => 37207, 20592 => 21465, + 20593 => 26093, 20594 => 24207, 20595 => 30044, 20596 => 24676, 20597 => 32110, + 20598 => 23167, 20599 => 32490, 20600 => 32493, 20601 => 36713, 20602 => 21927, + 20603 => 23459, 20604 => 24748, 20605 => 26059, 20606 => 29572, 20769 => 36873, + 20770 => 30307, 20771 => 30505, 20772 => 32474, 20773 => 38772, 20774 => 34203, + 20775 => 23398, 20776 => 31348, 20777 => 38634, 20778 => 34880, 20779 => 21195, + 20780 => 29071, 20781 => 24490, 20782 => 26092, 20783 => 35810, 20784 => 23547, + 20785 => 39535, 20786 => 24033, 20787 => 27529, 20788 => 27739, 20789 => 35757, + 20790 => 35759, 20791 => 36874, 20792 => 36805, 20793 => 21387, 20794 => 25276, + 20795 => 40486, 20796 => 40493, 20797 => 21568, 20798 => 20011, 20799 => 33469, + 20800 => 29273, 20801 => 34460, 20802 => 23830, 20803 => 34905, 20804 => 28079, + 20805 => 38597, 20806 => 21713, 20807 => 20122, 20808 => 35766, 20809 => 28937, + 20810 => 21693, 20811 => 38409, 20812 => 28895, 20813 => 28153, 20814 => 30416, + 20815 => 20005, 20816 => 30740, 20817 => 34578, 20818 => 23721, 20819 => 24310, + 20820 => 35328, 20821 => 39068, 20822 => 38414, 20823 => 28814, 20824 => 27839, + 20825 => 22852, 20826 => 25513, 20827 => 30524, 20828 => 34893, 20829 => 28436, + 20830 => 33395, 20831 => 22576, 20832 => 29141, 20833 => 21388, 20834 => 30746, + 20835 => 38593, 20836 => 21761, 20837 => 24422, 20838 => 28976, 20839 => 23476, + 20840 => 35866, 20841 => 39564, 20842 => 27523, 20843 => 22830, 20844 => 40495, + 20845 => 31207, 20846 => 26472, 20847 => 25196, 20848 => 20335, 20849 => 30113, + 20850 => 32650, 20851 => 27915, 20852 => 38451, 20853 => 27687, 20854 => 20208, + 20855 => 30162, 20856 => 20859, 20857 => 26679, 20858 => 28478, 20859 => 36992, + 20860 => 33136, 20861 => 22934, 20862 => 29814, 21025 => 25671, 21026 => 23591, + 21027 => 36965, 21028 => 31377, 21029 => 35875, 21030 => 23002, 21031 => 21676, + 21032 => 33280, 21033 => 33647, 21034 => 35201, 21035 => 32768, 21036 => 26928, + 21037 => 22094, 21038 => 32822, 21039 => 29239, 21040 => 37326, 21041 => 20918, + 21042 => 20063, 21043 => 39029, 21044 => 25494, 21045 => 19994, 21046 => 21494, + 21047 => 26355, 21048 => 33099, 21049 => 22812, 21050 => 28082, 21051 => 19968, + 21052 => 22777, 21053 => 21307, 21054 => 25558, 21055 => 38129, 21056 => 20381, + 21057 => 20234, 21058 => 34915, 21059 => 39056, 21060 => 22839, 21061 => 36951, + 21062 => 31227, 21063 => 20202, 21064 => 33008, 21065 => 30097, 21066 => 27778, + 21067 => 23452, 21068 => 23016, 21069 => 24413, 21070 => 26885, 21071 => 34433, + 21072 => 20506, 21073 => 24050, 21074 => 20057, 21075 => 30691, 21076 => 20197, + 21077 => 33402, 21078 => 25233, 21079 => 26131, 21080 => 37009, 21081 => 23673, + 21082 => 20159, 21083 => 24441, 21084 => 33222, 21085 => 36920, 21086 => 32900, + 21087 => 30123, 21088 => 20134, 21089 => 35028, 21090 => 24847, 21091 => 27589, + 21092 => 24518, 21093 => 20041, 21094 => 30410, 21095 => 28322, 21096 => 35811, + 21097 => 35758, 21098 => 35850, 21099 => 35793, 21100 => 24322, 21101 => 32764, + 21102 => 32716, 21103 => 32462, 21104 => 33589, 21105 => 33643, 21106 => 22240, + 21107 => 27575, 21108 => 38899, 21109 => 38452, 21110 => 23035, 21111 => 21535, + 21112 => 38134, 21113 => 28139, 21114 => 23493, 21115 => 39278, 21116 => 23609, + 21117 => 24341, 21118 => 38544, 21281 => 21360, 21282 => 33521, 21283 => 27185, + 21284 => 23156, 21285 => 40560, 21286 => 24212, 21287 => 32552, 21288 => 33721, + 21289 => 33828, 21290 => 33829, 21291 => 33639, 21292 => 34631, 21293 => 36814, + 21294 => 36194, 21295 => 30408, 21296 => 24433, 21297 => 39062, 21298 => 30828, + 21299 => 26144, 21300 => 21727, 21301 => 25317, 21302 => 20323, 21303 => 33219, + 21304 => 30152, 21305 => 24248, 21306 => 38605, 21307 => 36362, 21308 => 34553, + 21309 => 21647, 21310 => 27891, 21311 => 28044, 21312 => 27704, 21313 => 24703, + 21314 => 21191, 21315 => 29992, 21316 => 24189, 21317 => 20248, 21318 => 24736, + 21319 => 24551, 21320 => 23588, 21321 => 30001, 21322 => 37038, 21323 => 38080, + 21324 => 29369, 21325 => 27833, 21326 => 28216, 21327 => 37193, 21328 => 26377, + 21329 => 21451, 21330 => 21491, 21331 => 20305, 21332 => 37321, 21333 => 35825, + 21334 => 21448, 21335 => 24188, 21336 => 36802, 21337 => 28132, 21338 => 20110, + 21339 => 30402, 21340 => 27014, 21341 => 34398, 21342 => 24858, 21343 => 33286, + 21344 => 20313, 21345 => 20446, 21346 => 36926, 21347 => 40060, 21348 => 24841, + 21349 => 28189, 21350 => 28180, 21351 => 38533, 21352 => 20104, 21353 => 23089, + 21354 => 38632, 21355 => 19982, 21356 => 23679, 21357 => 31161, 21358 => 23431, + 21359 => 35821, 21360 => 32701, 21361 => 29577, 21362 => 22495, 21363 => 33419, + 21364 => 37057, 21365 => 21505, 21366 => 36935, 21367 => 21947, 21368 => 23786, + 21369 => 24481, 21370 => 24840, 21371 => 27442, 21372 => 29425, 21373 => 32946, + 21374 => 35465, 21537 => 28020, 21538 => 23507, 21539 => 35029, 21540 => 39044, + 21541 => 35947, 21542 => 39533, 21543 => 40499, 21544 => 28170, 21545 => 20900, + 21546 => 20803, 21547 => 22435, 21548 => 34945, 21549 => 21407, 21550 => 25588, + 21551 => 36757, 21552 => 22253, 21553 => 21592, 21554 => 22278, 21555 => 29503, + 21556 => 28304, 21557 => 32536, 21558 => 36828, 21559 => 33489, 21560 => 24895, + 21561 => 24616, 21562 => 38498, 21563 => 26352, 21564 => 32422, 21565 => 36234, + 21566 => 36291, 21567 => 38053, 21568 => 23731, 21569 => 31908, 21570 => 26376, + 21571 => 24742, 21572 => 38405, 21573 => 32792, 21574 => 20113, 21575 => 37095, + 21576 => 21248, 21577 => 38504, 21578 => 20801, 21579 => 36816, 21580 => 34164, + 21581 => 37213, 21582 => 26197, 21583 => 38901, 21584 => 23381, 21585 => 21277, + 21586 => 30776, 21587 => 26434, 21588 => 26685, 21589 => 21705, 21590 => 28798, + 21591 => 23472, 21592 => 36733, 21593 => 20877, 21594 => 22312, 21595 => 21681, + 21596 => 25874, 21597 => 26242, 21598 => 36190, 21599 => 36163, 21600 => 33039, + 21601 => 33900, 21602 => 36973, 21603 => 31967, 21604 => 20991, 21605 => 34299, + 21606 => 26531, 21607 => 26089, 21608 => 28577, 21609 => 34468, 21610 => 36481, + 21611 => 22122, 21612 => 36896, 21613 => 30338, 21614 => 28790, 21615 => 29157, + 21616 => 36131, 21617 => 25321, 21618 => 21017, 21619 => 27901, 21620 => 36156, + 21621 => 24590, 21622 => 22686, 21623 => 24974, 21624 => 26366, 21625 => 36192, + 21626 => 25166, 21627 => 21939, 21628 => 28195, 21629 => 26413, 21630 => 36711, + 21793 => 38113, 21794 => 38392, 21795 => 30504, 21796 => 26629, 21797 => 27048, + 21798 => 21643, 21799 => 20045, 21800 => 28856, 21801 => 35784, 21802 => 25688, + 21803 => 25995, 21804 => 23429, 21805 => 31364, 21806 => 20538, 21807 => 23528, + 21808 => 30651, 21809 => 27617, 21810 => 35449, 21811 => 31896, 21812 => 27838, + 21813 => 30415, 21814 => 26025, 21815 => 36759, 21816 => 23853, 21817 => 23637, + 21818 => 34360, 21819 => 26632, 21820 => 21344, 21821 => 25112, 21822 => 31449, + 21823 => 28251, 21824 => 32509, 21825 => 27167, 21826 => 31456, 21827 => 24432, + 21828 => 28467, 21829 => 24352, 21830 => 25484, 21831 => 28072, 21832 => 26454, + 21833 => 19976, 21834 => 24080, 21835 => 36134, 21836 => 20183, 21837 => 32960, + 21838 => 30260, 21839 => 38556, 21840 => 25307, 21841 => 26157, 21842 => 25214, + 21843 => 27836, 21844 => 36213, 21845 => 29031, 21846 => 32617, 21847 => 20806, + 21848 => 32903, 21849 => 21484, 21850 => 36974, 21851 => 25240, 21852 => 21746, + 21853 => 34544, 21854 => 36761, 21855 => 32773, 21856 => 38167, 21857 => 34071, + 21858 => 36825, 21859 => 27993, 21860 => 29645, 21861 => 26015, 21862 => 30495, + 21863 => 29956, 21864 => 30759, 21865 => 33275, 21866 => 36126, 21867 => 38024, + 21868 => 20390, 21869 => 26517, 21870 => 30137, 21871 => 35786, 21872 => 38663, + 21873 => 25391, 21874 => 38215, 21875 => 38453, 21876 => 33976, 21877 => 25379, + 21878 => 30529, 21879 => 24449, 21880 => 29424, 21881 => 20105, 21882 => 24596, + 21883 => 25972, 21884 => 25327, 21885 => 27491, 21886 => 25919, 22049 => 24103, + 22050 => 30151, 22051 => 37073, 22052 => 35777, 22053 => 33437, 22054 => 26525, + 22055 => 25903, 22056 => 21553, 22057 => 34584, 22058 => 30693, 22059 => 32930, + 22060 => 33026, 22061 => 27713, 22062 => 20043, 22063 => 32455, 22064 => 32844, + 22065 => 30452, 22066 => 26893, 22067 => 27542, 22068 => 25191, 22069 => 20540, + 22070 => 20356, 22071 => 22336, 22072 => 25351, 22073 => 27490, 22074 => 36286, + 22075 => 21482, 22076 => 26088, 22077 => 32440, 22078 => 24535, 22079 => 25370, + 22080 => 25527, 22081 => 33267, 22082 => 33268, 22083 => 32622, 22084 => 24092, + 22085 => 23769, 22086 => 21046, 22087 => 26234, 22088 => 31209, 22089 => 31258, + 22090 => 36136, 22091 => 28825, 22092 => 30164, 22093 => 28382, 22094 => 27835, + 22095 => 31378, 22096 => 20013, 22097 => 30405, 22098 => 24544, 22099 => 38047, + 22100 => 34935, 22101 => 32456, 22102 => 31181, 22103 => 32959, 22104 => 37325, + 22105 => 20210, 22106 => 20247, 22107 => 33311, 22108 => 21608, 22109 => 24030, + 22110 => 27954, 22111 => 35788, 22112 => 31909, 22113 => 36724, 22114 => 32920, + 22115 => 24090, 22116 => 21650, 22117 => 30385, 22118 => 23449, 22119 => 26172, + 22120 => 39588, 22121 => 29664, 22122 => 26666, 22123 => 34523, 22124 => 26417, + 22125 => 29482, 22126 => 35832, 22127 => 35803, 22128 => 36880, 22129 => 31481, + 22130 => 28891, 22131 => 29038, 22132 => 25284, 22133 => 30633, 22134 => 22065, + 22135 => 20027, 22136 => 33879, 22137 => 26609, 22138 => 21161, 22139 => 34496, + 22140 => 36142, 22141 => 38136, 22142 => 31569, 22305 => 20303, 22306 => 27880, + 22307 => 31069, 22308 => 39547, 22309 => 25235, 22310 => 29226, 22311 => 25341, + 22312 => 19987, 22313 => 30742, 22314 => 36716, 22315 => 25776, 22316 => 36186, + 22317 => 31686, 22318 => 26729, 22319 => 24196, 22320 => 35013, 22321 => 22918, + 22322 => 25758, 22323 => 22766, 22324 => 29366, 22325 => 26894, 22326 => 38181, + 22327 => 36861, 22328 => 36184, 22329 => 22368, 22330 => 32512, 22331 => 35846, + 22332 => 20934, 22333 => 25417, 22334 => 25305, 22335 => 21331, 22336 => 26700, + 22337 => 29730, 22338 => 33537, 22339 => 37196, 22340 => 21828, 22341 => 30528, + 22342 => 28796, 22343 => 27978, 22344 => 20857, 22345 => 21672, 22346 => 36164, + 22347 => 23039, 22348 => 28363, 22349 => 28100, 22350 => 23388, 22351 => 32043, + 22352 => 20180, 22353 => 31869, 22354 => 28371, 22355 => 23376, 22356 => 33258, + 22357 => 28173, 22358 => 23383, 22359 => 39683, 22360 => 26837, 22361 => 36394, + 22362 => 23447, 22363 => 32508, 22364 => 24635, 22365 => 32437, 22366 => 37049, + 22367 => 36208, 22368 => 22863, 22369 => 25549, 22370 => 31199, 22371 => 36275, + 22372 => 21330, 22373 => 26063, 22374 => 31062, 22375 => 35781, 22376 => 38459, + 22377 => 32452, 22378 => 38075, 22379 => 32386, 22380 => 22068, 22381 => 37257, + 22382 => 26368, 22383 => 32618, 22384 => 23562, 22385 => 36981, 22386 => 26152, + 22387 => 24038, 22388 => 20304, 22389 => 26590, 22390 => 20570, 22391 => 20316, + 22392 => 22352, 22393 => 24231, 22561 => 20109, 22562 => 19980, 22563 => 20800, + 22564 => 19984, 22565 => 24319, 22566 => 21317, 22567 => 19989, 22568 => 20120, + 22569 => 19998, 22570 => 39730, 22571 => 23404, 22572 => 22121, 22573 => 20008, + 22574 => 31162, 22575 => 20031, 22576 => 21269, 22577 => 20039, 22578 => 22829, + 22579 => 29243, 22580 => 21358, 22581 => 27664, 22582 => 22239, 22583 => 32996, + 22584 => 39319, 22585 => 27603, 22586 => 30590, 22587 => 40727, 22588 => 20022, + 22589 => 20127, 22590 => 40720, 22591 => 20060, 22592 => 20073, 22593 => 20115, + 22594 => 33416, 22595 => 23387, 22596 => 21868, 22597 => 22031, 22598 => 20164, + 22599 => 21389, 22600 => 21405, 22601 => 21411, 22602 => 21413, 22603 => 21422, + 22604 => 38757, 22605 => 36189, 22606 => 21274, 22607 => 21493, 22608 => 21286, + 22609 => 21294, 22610 => 21310, 22611 => 36188, 22612 => 21350, 22613 => 21347, + 22614 => 20994, 22615 => 21000, 22616 => 21006, 22617 => 21037, 22618 => 21043, + 22619 => 21055, 22620 => 21056, 22621 => 21068, 22622 => 21086, 22623 => 21089, + 22624 => 21084, 22625 => 33967, 22626 => 21117, 22627 => 21122, 22628 => 21121, + 22629 => 21136, 22630 => 21139, 22631 => 20866, 22632 => 32596, 22633 => 20155, + 22634 => 20163, 22635 => 20169, 22636 => 20162, 22637 => 20200, 22638 => 20193, + 22639 => 20203, 22640 => 20190, 22641 => 20251, 22642 => 20211, 22643 => 20258, + 22644 => 20324, 22645 => 20213, 22646 => 20261, 22647 => 20263, 22648 => 20233, + 22649 => 20267, 22650 => 20318, 22651 => 20327, 22652 => 25912, 22653 => 20314, + 22654 => 20317, 22817 => 20319, 22818 => 20311, 22819 => 20274, 22820 => 20285, + 22821 => 20342, 22822 => 20340, 22823 => 20369, 22824 => 20361, 22825 => 20355, + 22826 => 20367, 22827 => 20350, 22828 => 20347, 22829 => 20394, 22830 => 20348, + 22831 => 20396, 22832 => 20372, 22833 => 20454, 22834 => 20456, 22835 => 20458, + 22836 => 20421, 22837 => 20442, 22838 => 20451, 22839 => 20444, 22840 => 20433, + 22841 => 20447, 22842 => 20472, 22843 => 20521, 22844 => 20556, 22845 => 20467, + 22846 => 20524, 22847 => 20495, 22848 => 20526, 22849 => 20525, 22850 => 20478, + 22851 => 20508, 22852 => 20492, 22853 => 20517, 22854 => 20520, 22855 => 20606, + 22856 => 20547, 22857 => 20565, 22858 => 20552, 22859 => 20558, 22860 => 20588, + 22861 => 20603, 22862 => 20645, 22863 => 20647, 22864 => 20649, 22865 => 20666, + 22866 => 20694, 22867 => 20742, 22868 => 20717, 22869 => 20716, 22870 => 20710, + 22871 => 20718, 22872 => 20743, 22873 => 20747, 22874 => 20189, 22875 => 27709, + 22876 => 20312, 22877 => 20325, 22878 => 20430, 22879 => 40864, 22880 => 27718, + 22881 => 31860, 22882 => 20846, 22883 => 24061, 22884 => 40649, 22885 => 39320, + 22886 => 20865, 22887 => 22804, 22888 => 21241, 22889 => 21261, 22890 => 35335, + 22891 => 21264, 22892 => 20971, 22893 => 22809, 22894 => 20821, 22895 => 20128, + 22896 => 20822, 22897 => 20147, 22898 => 34926, 22899 => 34980, 22900 => 20149, + 22901 => 33044, 22902 => 35026, 22903 => 31104, 22904 => 23348, 22905 => 34819, + 22906 => 32696, 22907 => 20907, 22908 => 20913, 22909 => 20925, 22910 => 20924, + 23073 => 20935, 23074 => 20886, 23075 => 20898, 23076 => 20901, 23077 => 35744, + 23078 => 35750, 23079 => 35751, 23080 => 35754, 23081 => 35764, 23082 => 35765, + 23083 => 35767, 23084 => 35778, 23085 => 35779, 23086 => 35787, 23087 => 35791, + 23088 => 35790, 23089 => 35794, 23090 => 35795, 23091 => 35796, 23092 => 35798, + 23093 => 35800, 23094 => 35801, 23095 => 35804, 23096 => 35807, 23097 => 35808, + 23098 => 35812, 23099 => 35816, 23100 => 35817, 23101 => 35822, 23102 => 35824, + 23103 => 35827, 23104 => 35830, 23105 => 35833, 23106 => 35836, 23107 => 35839, + 23108 => 35840, 23109 => 35842, 23110 => 35844, 23111 => 35847, 23112 => 35852, + 23113 => 35855, 23114 => 35857, 23115 => 35858, 23116 => 35860, 23117 => 35861, + 23118 => 35862, 23119 => 35865, 23120 => 35867, 23121 => 35864, 23122 => 35869, + 23123 => 35871, 23124 => 35872, 23125 => 35873, 23126 => 35877, 23127 => 35879, + 23128 => 35882, 23129 => 35883, 23130 => 35886, 23131 => 35887, 23132 => 35890, + 23133 => 35891, 23134 => 35893, 23135 => 35894, 23136 => 21353, 23137 => 21370, + 23138 => 38429, 23139 => 38434, 23140 => 38433, 23141 => 38449, 23142 => 38442, + 23143 => 38461, 23144 => 38460, 23145 => 38466, 23146 => 38473, 23147 => 38484, + 23148 => 38495, 23149 => 38503, 23150 => 38508, 23151 => 38514, 23152 => 38516, + 23153 => 38536, 23154 => 38541, 23155 => 38551, 23156 => 38576, 23157 => 37015, + 23158 => 37019, 23159 => 37021, 23160 => 37017, 23161 => 37036, 23162 => 37025, + 23163 => 37044, 23164 => 37043, 23165 => 37046, 23166 => 37050, 23329 => 37048, + 23330 => 37040, 23331 => 37071, 23332 => 37061, 23333 => 37054, 23334 => 37072, + 23335 => 37060, 23336 => 37063, 23337 => 37075, 23338 => 37094, 23339 => 37090, + 23340 => 37084, 23341 => 37079, 23342 => 37083, 23343 => 37099, 23344 => 37103, + 23345 => 37118, 23346 => 37124, 23347 => 37154, 23348 => 37150, 23349 => 37155, + 23350 => 37169, 23351 => 37167, 23352 => 37177, 23353 => 37187, 23354 => 37190, + 23355 => 21005, 23356 => 22850, 23357 => 21154, 23358 => 21164, 23359 => 21165, + 23360 => 21182, 23361 => 21759, 23362 => 21200, 23363 => 21206, 23364 => 21232, + 23365 => 21471, 23366 => 29166, 23367 => 30669, 23368 => 24308, 23369 => 20981, + 23370 => 20988, 23371 => 39727, 23372 => 21430, 23373 => 24321, 23374 => 30042, + 23375 => 24047, 23376 => 22348, 23377 => 22441, 23378 => 22433, 23379 => 22654, + 23380 => 22716, 23381 => 22725, 23382 => 22737, 23383 => 22313, 23384 => 22316, + 23385 => 22314, 23386 => 22323, 23387 => 22329, 23388 => 22318, 23389 => 22319, + 23390 => 22364, 23391 => 22331, 23392 => 22338, 23393 => 22377, 23394 => 22405, + 23395 => 22379, 23396 => 22406, 23397 => 22396, 23398 => 22395, 23399 => 22376, + 23400 => 22381, 23401 => 22390, 23402 => 22387, 23403 => 22445, 23404 => 22436, + 23405 => 22412, 23406 => 22450, 23407 => 22479, 23408 => 22439, 23409 => 22452, + 23410 => 22419, 23411 => 22432, 23412 => 22485, 23413 => 22488, 23414 => 22490, + 23415 => 22489, 23416 => 22482, 23417 => 22456, 23418 => 22516, 23419 => 22511, + 23420 => 22520, 23421 => 22500, 23422 => 22493, 23585 => 22539, 23586 => 22541, + 23587 => 22525, 23588 => 22509, 23589 => 22528, 23590 => 22558, 23591 => 22553, + 23592 => 22596, 23593 => 22560, 23594 => 22629, 23595 => 22636, 23596 => 22657, + 23597 => 22665, 23598 => 22682, 23599 => 22656, 23600 => 39336, 23601 => 40729, + 23602 => 25087, 23603 => 33401, 23604 => 33405, 23605 => 33407, 23606 => 33423, + 23607 => 33418, 23608 => 33448, 23609 => 33412, 23610 => 33422, 23611 => 33425, + 23612 => 33431, 23613 => 33433, 23614 => 33451, 23615 => 33464, 23616 => 33470, + 23617 => 33456, 23618 => 33480, 23619 => 33482, 23620 => 33507, 23621 => 33432, + 23622 => 33463, 23623 => 33454, 23624 => 33483, 23625 => 33484, 23626 => 33473, + 23627 => 33449, 23628 => 33460, 23629 => 33441, 23630 => 33450, 23631 => 33439, + 23632 => 33476, 23633 => 33486, 23634 => 33444, 23635 => 33505, 23636 => 33545, + 23637 => 33527, 23638 => 33508, 23639 => 33551, 23640 => 33543, 23641 => 33500, + 23642 => 33524, 23643 => 33490, 23644 => 33496, 23645 => 33548, 23646 => 33531, + 23647 => 33491, 23648 => 33553, 23649 => 33562, 23650 => 33542, 23651 => 33556, + 23652 => 33557, 23653 => 33504, 23654 => 33493, 23655 => 33564, 23656 => 33617, + 23657 => 33627, 23658 => 33628, 23659 => 33544, 23660 => 33682, 23661 => 33596, + 23662 => 33588, 23663 => 33585, 23664 => 33691, 23665 => 33630, 23666 => 33583, + 23667 => 33615, 23668 => 33607, 23669 => 33603, 23670 => 33631, 23671 => 33600, + 23672 => 33559, 23673 => 33632, 23674 => 33581, 23675 => 33594, 23676 => 33587, + 23677 => 33638, 23678 => 33637, 23841 => 33640, 23842 => 33563, 23843 => 33641, + 23844 => 33644, 23845 => 33642, 23846 => 33645, 23847 => 33646, 23848 => 33712, + 23849 => 33656, 23850 => 33715, 23851 => 33716, 23852 => 33696, 23853 => 33706, + 23854 => 33683, 23855 => 33692, 23856 => 33669, 23857 => 33660, 23858 => 33718, + 23859 => 33705, 23860 => 33661, 23861 => 33720, 23862 => 33659, 23863 => 33688, + 23864 => 33694, 23865 => 33704, 23866 => 33722, 23867 => 33724, 23868 => 33729, + 23869 => 33793, 23870 => 33765, 23871 => 33752, 23872 => 22535, 23873 => 33816, + 23874 => 33803, 23875 => 33757, 23876 => 33789, 23877 => 33750, 23878 => 33820, + 23879 => 33848, 23880 => 33809, 23881 => 33798, 23882 => 33748, 23883 => 33759, + 23884 => 33807, 23885 => 33795, 23886 => 33784, 23887 => 33785, 23888 => 33770, + 23889 => 33733, 23890 => 33728, 23891 => 33830, 23892 => 33776, 23893 => 33761, + 23894 => 33884, 23895 => 33873, 23896 => 33882, 23897 => 33881, 23898 => 33907, + 23899 => 33927, 23900 => 33928, 23901 => 33914, 23902 => 33929, 23903 => 33912, + 23904 => 33852, 23905 => 33862, 23906 => 33897, 23907 => 33910, 23908 => 33932, + 23909 => 33934, 23910 => 33841, 23911 => 33901, 23912 => 33985, 23913 => 33997, + 23914 => 34000, 23915 => 34022, 23916 => 33981, 23917 => 34003, 23918 => 33994, + 23919 => 33983, 23920 => 33978, 23921 => 34016, 23922 => 33953, 23923 => 33977, + 23924 => 33972, 23925 => 33943, 23926 => 34021, 23927 => 34019, 23928 => 34060, + 23929 => 29965, 23930 => 34104, 23931 => 34032, 23932 => 34105, 23933 => 34079, + 23934 => 34106, 24097 => 34134, 24098 => 34107, 24099 => 34047, 24100 => 34044, + 24101 => 34137, 24102 => 34120, 24103 => 34152, 24104 => 34148, 24105 => 34142, + 24106 => 34170, 24107 => 30626, 24108 => 34115, 24109 => 34162, 24110 => 34171, + 24111 => 34212, 24112 => 34216, 24113 => 34183, 24114 => 34191, 24115 => 34169, + 24116 => 34222, 24117 => 34204, 24118 => 34181, 24119 => 34233, 24120 => 34231, + 24121 => 34224, 24122 => 34259, 24123 => 34241, 24124 => 34268, 24125 => 34303, + 24126 => 34343, 24127 => 34309, 24128 => 34345, 24129 => 34326, 24130 => 34364, + 24131 => 24318, 24132 => 24328, 24133 => 22844, 24134 => 22849, 24135 => 32823, + 24136 => 22869, 24137 => 22874, 24138 => 22872, 24139 => 21263, 24140 => 23586, + 24141 => 23589, 24142 => 23596, 24143 => 23604, 24144 => 25164, 24145 => 25194, + 24146 => 25247, 24147 => 25275, 24148 => 25290, 24149 => 25306, 24150 => 25303, + 24151 => 25326, 24152 => 25378, 24153 => 25334, 24154 => 25401, 24155 => 25419, + 24156 => 25411, 24157 => 25517, 24158 => 25590, 24159 => 25457, 24160 => 25466, + 24161 => 25486, 24162 => 25524, 24163 => 25453, 24164 => 25516, 24165 => 25482, + 24166 => 25449, 24167 => 25518, 24168 => 25532, 24169 => 25586, 24170 => 25592, + 24171 => 25568, 24172 => 25599, 24173 => 25540, 24174 => 25566, 24175 => 25550, + 24176 => 25682, 24177 => 25542, 24178 => 25534, 24179 => 25669, 24180 => 25665, + 24181 => 25611, 24182 => 25627, 24183 => 25632, 24184 => 25612, 24185 => 25638, + 24186 => 25633, 24187 => 25694, 24188 => 25732, 24189 => 25709, 24190 => 25750, + 24353 => 25722, 24354 => 25783, 24355 => 25784, 24356 => 25753, 24357 => 25786, + 24358 => 25792, 24359 => 25808, 24360 => 25815, 24361 => 25828, 24362 => 25826, + 24363 => 25865, 24364 => 25893, 24365 => 25902, 24366 => 24331, 24367 => 24530, + 24368 => 29977, 24369 => 24337, 24370 => 21343, 24371 => 21489, 24372 => 21501, + 24373 => 21481, 24374 => 21480, 24375 => 21499, 24376 => 21522, 24377 => 21526, + 24378 => 21510, 24379 => 21579, 24380 => 21586, 24381 => 21587, 24382 => 21588, + 24383 => 21590, 24384 => 21571, 24385 => 21537, 24386 => 21591, 24387 => 21593, + 24388 => 21539, 24389 => 21554, 24390 => 21634, 24391 => 21652, 24392 => 21623, + 24393 => 21617, 24394 => 21604, 24395 => 21658, 24396 => 21659, 24397 => 21636, + 24398 => 21622, 24399 => 21606, 24400 => 21661, 24401 => 21712, 24402 => 21677, + 24403 => 21698, 24404 => 21684, 24405 => 21714, 24406 => 21671, 24407 => 21670, + 24408 => 21715, 24409 => 21716, 24410 => 21618, 24411 => 21667, 24412 => 21717, + 24413 => 21691, 24414 => 21695, 24415 => 21708, 24416 => 21721, 24417 => 21722, + 24418 => 21724, 24419 => 21673, 24420 => 21674, 24421 => 21668, 24422 => 21725, + 24423 => 21711, 24424 => 21726, 24425 => 21787, 24426 => 21735, 24427 => 21792, + 24428 => 21757, 24429 => 21780, 24430 => 21747, 24431 => 21794, 24432 => 21795, + 24433 => 21775, 24434 => 21777, 24435 => 21799, 24436 => 21802, 24437 => 21863, + 24438 => 21903, 24439 => 21941, 24440 => 21833, 24441 => 21869, 24442 => 21825, + 24443 => 21845, 24444 => 21823, 24445 => 21840, 24446 => 21820, 24609 => 21815, + 24610 => 21846, 24611 => 21877, 24612 => 21878, 24613 => 21879, 24614 => 21811, + 24615 => 21808, 24616 => 21852, 24617 => 21899, 24618 => 21970, 24619 => 21891, + 24620 => 21937, 24621 => 21945, 24622 => 21896, 24623 => 21889, 24624 => 21919, + 24625 => 21886, 24626 => 21974, 24627 => 21905, 24628 => 21883, 24629 => 21983, + 24630 => 21949, 24631 => 21950, 24632 => 21908, 24633 => 21913, 24634 => 21994, + 24635 => 22007, 24636 => 21961, 24637 => 22047, 24638 => 21969, 24639 => 21995, + 24640 => 21996, 24641 => 21972, 24642 => 21990, 24643 => 21981, 24644 => 21956, + 24645 => 21999, 24646 => 21989, 24647 => 22002, 24648 => 22003, 24649 => 21964, + 24650 => 21965, 24651 => 21992, 24652 => 22005, 24653 => 21988, 24654 => 36756, + 24655 => 22046, 24656 => 22024, 24657 => 22028, 24658 => 22017, 24659 => 22052, + 24660 => 22051, 24661 => 22014, 24662 => 22016, 24663 => 22055, 24664 => 22061, + 24665 => 22104, 24666 => 22073, 24667 => 22103, 24668 => 22060, 24669 => 22093, + 24670 => 22114, 24671 => 22105, 24672 => 22108, 24673 => 22092, 24674 => 22100, + 24675 => 22150, 24676 => 22116, 24677 => 22129, 24678 => 22123, 24679 => 22139, + 24680 => 22140, 24681 => 22149, 24682 => 22163, 24683 => 22191, 24684 => 22228, + 24685 => 22231, 24686 => 22237, 24687 => 22241, 24688 => 22261, 24689 => 22251, + 24690 => 22265, 24691 => 22271, 24692 => 22276, 24693 => 22282, 24694 => 22281, + 24695 => 22300, 24696 => 24079, 24697 => 24089, 24698 => 24084, 24699 => 24081, + 24700 => 24113, 24701 => 24123, 24702 => 24124, 24865 => 24119, 24866 => 24132, + 24867 => 24148, 24868 => 24155, 24869 => 24158, 24870 => 24161, 24871 => 23692, + 24872 => 23674, 24873 => 23693, 24874 => 23696, 24875 => 23702, 24876 => 23688, + 24877 => 23704, 24878 => 23705, 24879 => 23697, 24880 => 23706, 24881 => 23708, + 24882 => 23733, 24883 => 23714, 24884 => 23741, 24885 => 23724, 24886 => 23723, + 24887 => 23729, 24888 => 23715, 24889 => 23745, 24890 => 23735, 24891 => 23748, + 24892 => 23762, 24893 => 23780, 24894 => 23755, 24895 => 23781, 24896 => 23810, + 24897 => 23811, 24898 => 23847, 24899 => 23846, 24900 => 23854, 24901 => 23844, + 24902 => 23838, 24903 => 23814, 24904 => 23835, 24905 => 23896, 24906 => 23870, + 24907 => 23860, 24908 => 23869, 24909 => 23916, 24910 => 23899, 24911 => 23919, + 24912 => 23901, 24913 => 23915, 24914 => 23883, 24915 => 23882, 24916 => 23913, + 24917 => 23924, 24918 => 23938, 24919 => 23961, 24920 => 23965, 24921 => 35955, + 24922 => 23991, 24923 => 24005, 24924 => 24435, 24925 => 24439, 24926 => 24450, + 24927 => 24455, 24928 => 24457, 24929 => 24460, 24930 => 24469, 24931 => 24473, + 24932 => 24476, 24933 => 24488, 24934 => 24493, 24935 => 24501, 24936 => 24508, + 24937 => 34914, 24938 => 24417, 24939 => 29357, 24940 => 29360, 24941 => 29364, + 24942 => 29367, 24943 => 29368, 24944 => 29379, 24945 => 29377, 24946 => 29390, + 24947 => 29389, 24948 => 29394, 24949 => 29416, 24950 => 29423, 24951 => 29417, + 24952 => 29426, 24953 => 29428, 24954 => 29431, 24955 => 29441, 24956 => 29427, + 24957 => 29443, 24958 => 29434, 25121 => 29435, 25122 => 29463, 25123 => 29459, + 25124 => 29473, 25125 => 29450, 25126 => 29470, 25127 => 29469, 25128 => 29461, + 25129 => 29474, 25130 => 29497, 25131 => 29477, 25132 => 29484, 25133 => 29496, + 25134 => 29489, 25135 => 29520, 25136 => 29517, 25137 => 29527, 25138 => 29536, + 25139 => 29548, 25140 => 29551, 25141 => 29566, 25142 => 33307, 25143 => 22821, + 25144 => 39143, 25145 => 22820, 25146 => 22786, 25147 => 39267, 25148 => 39271, + 25149 => 39272, 25150 => 39273, 25151 => 39274, 25152 => 39275, 25153 => 39276, + 25154 => 39284, 25155 => 39287, 25156 => 39293, 25157 => 39296, 25158 => 39300, + 25159 => 39303, 25160 => 39306, 25161 => 39309, 25162 => 39312, 25163 => 39313, + 25164 => 39315, 25165 => 39316, 25166 => 39317, 25167 => 24192, 25168 => 24209, + 25169 => 24203, 25170 => 24214, 25171 => 24229, 25172 => 24224, 25173 => 24249, + 25174 => 24245, 25175 => 24254, 25176 => 24243, 25177 => 36179, 25178 => 24274, + 25179 => 24273, 25180 => 24283, 25181 => 24296, 25182 => 24298, 25183 => 33210, + 25184 => 24516, 25185 => 24521, 25186 => 24534, 25187 => 24527, 25188 => 24579, + 25189 => 24558, 25190 => 24580, 25191 => 24545, 25192 => 24548, 25193 => 24574, + 25194 => 24581, 25195 => 24582, 25196 => 24554, 25197 => 24557, 25198 => 24568, + 25199 => 24601, 25200 => 24629, 25201 => 24614, 25202 => 24603, 25203 => 24591, + 25204 => 24589, 25205 => 24617, 25206 => 24619, 25207 => 24586, 25208 => 24639, + 25209 => 24609, 25210 => 24696, 25211 => 24697, 25212 => 24699, 25213 => 24698, + 25214 => 24642, 25377 => 24682, 25378 => 24701, 25379 => 24726, 25380 => 24730, + 25381 => 24749, 25382 => 24733, 25383 => 24707, 25384 => 24722, 25385 => 24716, + 25386 => 24731, 25387 => 24812, 25388 => 24763, 25389 => 24753, 25390 => 24797, + 25391 => 24792, 25392 => 24774, 25393 => 24794, 25394 => 24756, 25395 => 24864, + 25396 => 24870, 25397 => 24853, 25398 => 24867, 25399 => 24820, 25400 => 24832, + 25401 => 24846, 25402 => 24875, 25403 => 24906, 25404 => 24949, 25405 => 25004, + 25406 => 24980, 25407 => 24999, 25408 => 25015, 25409 => 25044, 25410 => 25077, + 25411 => 24541, 25412 => 38579, 25413 => 38377, 25414 => 38379, 25415 => 38385, + 25416 => 38387, 25417 => 38389, 25418 => 38390, 25419 => 38396, 25420 => 38398, + 25421 => 38403, 25422 => 38404, 25423 => 38406, 25424 => 38408, 25425 => 38410, + 25426 => 38411, 25427 => 38412, 25428 => 38413, 25429 => 38415, 25430 => 38418, + 25431 => 38421, 25432 => 38422, 25433 => 38423, 25434 => 38425, 25435 => 38426, + 25436 => 20012, 25437 => 29247, 25438 => 25109, 25439 => 27701, 25440 => 27732, + 25441 => 27740, 25442 => 27722, 25443 => 27811, 25444 => 27781, 25445 => 27792, + 25446 => 27796, 25447 => 27788, 25448 => 27752, 25449 => 27753, 25450 => 27764, + 25451 => 27766, 25452 => 27782, 25453 => 27817, 25454 => 27856, 25455 => 27860, + 25456 => 27821, 25457 => 27895, 25458 => 27896, 25459 => 27889, 25460 => 27863, + 25461 => 27826, 25462 => 27872, 25463 => 27862, 25464 => 27898, 25465 => 27883, + 25466 => 27886, 25467 => 27825, 25468 => 27859, 25469 => 27887, 25470 => 27902, + 25633 => 27961, 25634 => 27943, 25635 => 27916, 25636 => 27971, 25637 => 27976, + 25638 => 27911, 25639 => 27908, 25640 => 27929, 25641 => 27918, 25642 => 27947, + 25643 => 27981, 25644 => 27950, 25645 => 27957, 25646 => 27930, 25647 => 27983, + 25648 => 27986, 25649 => 27988, 25650 => 27955, 25651 => 28049, 25652 => 28015, + 25653 => 28062, 25654 => 28064, 25655 => 27998, 25656 => 28051, 25657 => 28052, + 25658 => 27996, 25659 => 28000, 25660 => 28028, 25661 => 28003, 25662 => 28186, + 25663 => 28103, 25664 => 28101, 25665 => 28126, 25666 => 28174, 25667 => 28095, + 25668 => 28128, 25669 => 28177, 25670 => 28134, 25671 => 28125, 25672 => 28121, + 25673 => 28182, 25674 => 28075, 25675 => 28172, 25676 => 28078, 25677 => 28203, + 25678 => 28270, 25679 => 28238, 25680 => 28267, 25681 => 28338, 25682 => 28255, + 25683 => 28294, 25684 => 28243, 25685 => 28244, 25686 => 28210, 25687 => 28197, + 25688 => 28228, 25689 => 28383, 25690 => 28337, 25691 => 28312, 25692 => 28384, + 25693 => 28461, 25694 => 28386, 25695 => 28325, 25696 => 28327, 25697 => 28349, + 25698 => 28347, 25699 => 28343, 25700 => 28375, 25701 => 28340, 25702 => 28367, + 25703 => 28303, 25704 => 28354, 25705 => 28319, 25706 => 28514, 25707 => 28486, + 25708 => 28487, 25709 => 28452, 25710 => 28437, 25711 => 28409, 25712 => 28463, + 25713 => 28470, 25714 => 28491, 25715 => 28532, 25716 => 28458, 25717 => 28425, + 25718 => 28457, 25719 => 28553, 25720 => 28557, 25721 => 28556, 25722 => 28536, + 25723 => 28530, 25724 => 28540, 25725 => 28538, 25726 => 28625, 25889 => 28617, + 25890 => 28583, 25891 => 28601, 25892 => 28598, 25893 => 28610, 25894 => 28641, + 25895 => 28654, 25896 => 28638, 25897 => 28640, 25898 => 28655, 25899 => 28698, + 25900 => 28707, 25901 => 28699, 25902 => 28729, 25903 => 28725, 25904 => 28751, + 25905 => 28766, 25906 => 23424, 25907 => 23428, 25908 => 23445, 25909 => 23443, + 25910 => 23461, 25911 => 23480, 25912 => 29999, 25913 => 39582, 25914 => 25652, + 25915 => 23524, 25916 => 23534, 25917 => 35120, 25918 => 23536, 25919 => 36423, + 25920 => 35591, 25921 => 36790, 25922 => 36819, 25923 => 36821, 25924 => 36837, + 25925 => 36846, 25926 => 36836, 25927 => 36841, 25928 => 36838, 25929 => 36851, + 25930 => 36840, 25931 => 36869, 25932 => 36868, 25933 => 36875, 25934 => 36902, + 25935 => 36881, 25936 => 36877, 25937 => 36886, 25938 => 36897, 25939 => 36917, + 25940 => 36918, 25941 => 36909, 25942 => 36911, 25943 => 36932, 25944 => 36945, + 25945 => 36946, 25946 => 36944, 25947 => 36968, 25948 => 36952, 25949 => 36962, + 25950 => 36955, 25951 => 26297, 25952 => 36980, 25953 => 36989, 25954 => 36994, + 25955 => 37000, 25956 => 36995, 25957 => 37003, 25958 => 24400, 25959 => 24407, + 25960 => 24406, 25961 => 24408, 25962 => 23611, 25963 => 21675, 25964 => 23632, + 25965 => 23641, 25966 => 23409, 25967 => 23651, 25968 => 23654, 25969 => 32700, + 25970 => 24362, 25971 => 24361, 25972 => 24365, 25973 => 33396, 25974 => 24380, + 25975 => 39739, 25976 => 23662, 25977 => 22913, 25978 => 22915, 25979 => 22925, + 25980 => 22953, 25981 => 22954, 25982 => 22947, 26145 => 22935, 26146 => 22986, + 26147 => 22955, 26148 => 22942, 26149 => 22948, 26150 => 22994, 26151 => 22962, + 26152 => 22959, 26153 => 22999, 26154 => 22974, 26155 => 23045, 26156 => 23046, + 26157 => 23005, 26158 => 23048, 26159 => 23011, 26160 => 23000, 26161 => 23033, + 26162 => 23052, 26163 => 23049, 26164 => 23090, 26165 => 23092, 26166 => 23057, + 26167 => 23075, 26168 => 23059, 26169 => 23104, 26170 => 23143, 26171 => 23114, + 26172 => 23125, 26173 => 23100, 26174 => 23138, 26175 => 23157, 26176 => 33004, + 26177 => 23210, 26178 => 23195, 26179 => 23159, 26180 => 23162, 26181 => 23230, + 26182 => 23275, 26183 => 23218, 26184 => 23250, 26185 => 23252, 26186 => 23224, + 26187 => 23264, 26188 => 23267, 26189 => 23281, 26190 => 23254, 26191 => 23270, + 26192 => 23256, 26193 => 23260, 26194 => 23305, 26195 => 23319, 26196 => 23318, + 26197 => 23346, 26198 => 23351, 26199 => 23360, 26200 => 23573, 26201 => 23580, + 26202 => 23386, 26203 => 23397, 26204 => 23411, 26205 => 23377, 26206 => 23379, + 26207 => 23394, 26208 => 39541, 26209 => 39543, 26210 => 39544, 26211 => 39546, + 26212 => 39551, 26213 => 39549, 26214 => 39552, 26215 => 39553, 26216 => 39557, + 26217 => 39560, 26218 => 39562, 26219 => 39568, 26220 => 39570, 26221 => 39571, + 26222 => 39574, 26223 => 39576, 26224 => 39579, 26225 => 39580, 26226 => 39581, + 26227 => 39583, 26228 => 39584, 26229 => 39586, 26230 => 39587, 26231 => 39589, + 26232 => 39591, 26233 => 32415, 26234 => 32417, 26235 => 32419, 26236 => 32421, + 26237 => 32424, 26238 => 32425, 26401 => 32429, 26402 => 32432, 26403 => 32446, + 26404 => 32448, 26405 => 32449, 26406 => 32450, 26407 => 32457, 26408 => 32459, + 26409 => 32460, 26410 => 32464, 26411 => 32468, 26412 => 32471, 26413 => 32475, + 26414 => 32480, 26415 => 32481, 26416 => 32488, 26417 => 32491, 26418 => 32494, + 26419 => 32495, 26420 => 32497, 26421 => 32498, 26422 => 32525, 26423 => 32502, + 26424 => 32506, 26425 => 32507, 26426 => 32510, 26427 => 32513, 26428 => 32514, + 26429 => 32515, 26430 => 32519, 26431 => 32520, 26432 => 32523, 26433 => 32524, + 26434 => 32527, 26435 => 32529, 26436 => 32530, 26437 => 32535, 26438 => 32537, + 26439 => 32540, 26440 => 32539, 26441 => 32543, 26442 => 32545, 26443 => 32546, + 26444 => 32547, 26445 => 32548, 26446 => 32549, 26447 => 32550, 26448 => 32551, + 26449 => 32554, 26450 => 32555, 26451 => 32556, 26452 => 32557, 26453 => 32559, + 26454 => 32560, 26455 => 32561, 26456 => 32562, 26457 => 32563, 26458 => 32565, + 26459 => 24186, 26460 => 30079, 26461 => 24027, 26462 => 30014, 26463 => 37013, + 26464 => 29582, 26465 => 29585, 26466 => 29614, 26467 => 29602, 26468 => 29599, + 26469 => 29647, 26470 => 29634, 26471 => 29649, 26472 => 29623, 26473 => 29619, + 26474 => 29632, 26475 => 29641, 26476 => 29640, 26477 => 29669, 26478 => 29657, + 26479 => 39036, 26480 => 29706, 26481 => 29673, 26482 => 29671, 26483 => 29662, + 26484 => 29626, 26485 => 29682, 26486 => 29711, 26487 => 29738, 26488 => 29787, + 26489 => 29734, 26490 => 29733, 26491 => 29736, 26492 => 29744, 26493 => 29742, + 26494 => 29740, 26657 => 29723, 26658 => 29722, 26659 => 29761, 26660 => 29788, + 26661 => 29783, 26662 => 29781, 26663 => 29785, 26664 => 29815, 26665 => 29805, + 26666 => 29822, 26667 => 29852, 26668 => 29838, 26669 => 29824, 26670 => 29825, + 26671 => 29831, 26672 => 29835, 26673 => 29854, 26674 => 29864, 26675 => 29865, + 26676 => 29840, 26677 => 29863, 26678 => 29906, 26679 => 29882, 26680 => 38890, + 26681 => 38891, 26682 => 38892, 26683 => 26444, 26684 => 26451, 26685 => 26462, + 26686 => 26440, 26687 => 26473, 26688 => 26533, 26689 => 26503, 26690 => 26474, + 26691 => 26483, 26692 => 26520, 26693 => 26535, 26694 => 26485, 26695 => 26536, + 26696 => 26526, 26697 => 26541, 26698 => 26507, 26699 => 26487, 26700 => 26492, + 26701 => 26608, 26702 => 26633, 26703 => 26584, 26704 => 26634, 26705 => 26601, + 26706 => 26544, 26707 => 26636, 26708 => 26585, 26709 => 26549, 26710 => 26586, + 26711 => 26547, 26712 => 26589, 26713 => 26624, 26714 => 26563, 26715 => 26552, + 26716 => 26594, 26717 => 26638, 26718 => 26561, 26719 => 26621, 26720 => 26674, + 26721 => 26675, 26722 => 26720, 26723 => 26721, 26724 => 26702, 26725 => 26722, + 26726 => 26692, 26727 => 26724, 26728 => 26755, 26729 => 26653, 26730 => 26709, + 26731 => 26726, 26732 => 26689, 26733 => 26727, 26734 => 26688, 26735 => 26686, + 26736 => 26698, 26737 => 26697, 26738 => 26665, 26739 => 26805, 26740 => 26767, + 26741 => 26740, 26742 => 26743, 26743 => 26771, 26744 => 26731, 26745 => 26818, + 26746 => 26990, 26747 => 26876, 26748 => 26911, 26749 => 26912, 26750 => 26873, + 26913 => 26916, 26914 => 26864, 26915 => 26891, 26916 => 26881, 26917 => 26967, + 26918 => 26851, 26919 => 26896, 26920 => 26993, 26921 => 26937, 26922 => 26976, + 26923 => 26946, 26924 => 26973, 26925 => 27012, 26926 => 26987, 26927 => 27008, + 26928 => 27032, 26929 => 27000, 26930 => 26932, 26931 => 27084, 26932 => 27015, + 26933 => 27016, 26934 => 27086, 26935 => 27017, 26936 => 26982, 26937 => 26979, + 26938 => 27001, 26939 => 27035, 26940 => 27047, 26941 => 27067, 26942 => 27051, + 26943 => 27053, 26944 => 27092, 26945 => 27057, 26946 => 27073, 26947 => 27082, + 26948 => 27103, 26949 => 27029, 26950 => 27104, 26951 => 27021, 26952 => 27135, + 26953 => 27183, 26954 => 27117, 26955 => 27159, 26956 => 27160, 26957 => 27237, + 26958 => 27122, 26959 => 27204, 26960 => 27198, 26961 => 27296, 26962 => 27216, + 26963 => 27227, 26964 => 27189, 26965 => 27278, 26966 => 27257, 26967 => 27197, + 26968 => 27176, 26969 => 27224, 26970 => 27260, 26971 => 27281, 26972 => 27280, + 26973 => 27305, 26974 => 27287, 26975 => 27307, 26976 => 29495, 26977 => 29522, + 26978 => 27521, 26979 => 27522, 26980 => 27527, 26981 => 27524, 26982 => 27538, + 26983 => 27539, 26984 => 27533, 26985 => 27546, 26986 => 27547, 26987 => 27553, + 26988 => 27562, 26989 => 36715, 26990 => 36717, 26991 => 36721, 26992 => 36722, + 26993 => 36723, 26994 => 36725, 26995 => 36726, 26996 => 36728, 26997 => 36727, + 26998 => 36729, 26999 => 36730, 27000 => 36732, 27001 => 36734, 27002 => 36737, + 27003 => 36738, 27004 => 36740, 27005 => 36743, 27006 => 36747, 27169 => 36749, + 27170 => 36750, 27171 => 36751, 27172 => 36760, 27173 => 36762, 27174 => 36558, + 27175 => 25099, 27176 => 25111, 27177 => 25115, 27178 => 25119, 27179 => 25122, + 27180 => 25121, 27181 => 25125, 27182 => 25124, 27183 => 25132, 27184 => 33255, + 27185 => 29935, 27186 => 29940, 27187 => 29951, 27188 => 29967, 27189 => 29969, + 27190 => 29971, 27191 => 25908, 27192 => 26094, 27193 => 26095, 27194 => 26096, + 27195 => 26122, 27196 => 26137, 27197 => 26482, 27198 => 26115, 27199 => 26133, + 27200 => 26112, 27201 => 28805, 27202 => 26359, 27203 => 26141, 27204 => 26164, + 27205 => 26161, 27206 => 26166, 27207 => 26165, 27208 => 32774, 27209 => 26207, + 27210 => 26196, 27211 => 26177, 27212 => 26191, 27213 => 26198, 27214 => 26209, + 27215 => 26199, 27216 => 26231, 27217 => 26244, 27218 => 26252, 27219 => 26279, + 27220 => 26269, 27221 => 26302, 27222 => 26331, 27223 => 26332, 27224 => 26342, + 27225 => 26345, 27226 => 36146, 27227 => 36147, 27228 => 36150, 27229 => 36155, + 27230 => 36157, 27231 => 36160, 27232 => 36165, 27233 => 36166, 27234 => 36168, + 27235 => 36169, 27236 => 36167, 27237 => 36173, 27238 => 36181, 27239 => 36185, + 27240 => 35271, 27241 => 35274, 27242 => 35275, 27243 => 35276, 27244 => 35278, + 27245 => 35279, 27246 => 35280, 27247 => 35281, 27248 => 29294, 27249 => 29343, + 27250 => 29277, 27251 => 29286, 27252 => 29295, 27253 => 29310, 27254 => 29311, + 27255 => 29316, 27256 => 29323, 27257 => 29325, 27258 => 29327, 27259 => 29330, + 27260 => 25352, 27261 => 25394, 27262 => 25520, 27425 => 25663, 27426 => 25816, + 27427 => 32772, 27428 => 27626, 27429 => 27635, 27430 => 27645, 27431 => 27637, + 27432 => 27641, 27433 => 27653, 27434 => 27655, 27435 => 27654, 27436 => 27661, + 27437 => 27669, 27438 => 27672, 27439 => 27673, 27440 => 27674, 27441 => 27681, + 27442 => 27689, 27443 => 27684, 27444 => 27690, 27445 => 27698, 27446 => 25909, + 27447 => 25941, 27448 => 25963, 27449 => 29261, 27450 => 29266, 27451 => 29270, + 27452 => 29232, 27453 => 34402, 27454 => 21014, 27455 => 32927, 27456 => 32924, + 27457 => 32915, 27458 => 32956, 27459 => 26378, 27460 => 32957, 27461 => 32945, + 27462 => 32939, 27463 => 32941, 27464 => 32948, 27465 => 32951, 27466 => 32999, + 27467 => 33000, 27468 => 33001, 27469 => 33002, 27470 => 32987, 27471 => 32962, + 27472 => 32964, 27473 => 32985, 27474 => 32973, 27475 => 32983, 27476 => 26384, + 27477 => 32989, 27478 => 33003, 27479 => 33009, 27480 => 33012, 27481 => 33005, + 27482 => 33037, 27483 => 33038, 27484 => 33010, 27485 => 33020, 27486 => 26389, + 27487 => 33042, 27488 => 35930, 27489 => 33078, 27490 => 33054, 27491 => 33068, + 27492 => 33048, 27493 => 33074, 27494 => 33096, 27495 => 33100, 27496 => 33107, + 27497 => 33140, 27498 => 33113, 27499 => 33114, 27500 => 33137, 27501 => 33120, + 27502 => 33129, 27503 => 33148, 27504 => 33149, 27505 => 33133, 27506 => 33127, + 27507 => 22605, 27508 => 23221, 27509 => 33160, 27510 => 33154, 27511 => 33169, + 27512 => 28373, 27513 => 33187, 27514 => 33194, 27515 => 33228, 27516 => 26406, + 27517 => 33226, 27518 => 33211, 27681 => 33217, 27682 => 33190, 27683 => 27428, + 27684 => 27447, 27685 => 27449, 27686 => 27459, 27687 => 27462, 27688 => 27481, + 27689 => 39121, 27690 => 39122, 27691 => 39123, 27692 => 39125, 27693 => 39129, + 27694 => 39130, 27695 => 27571, 27696 => 24384, 27697 => 27586, 27698 => 35315, + 27699 => 26000, 27700 => 40785, 27701 => 26003, 27702 => 26044, 27703 => 26054, + 27704 => 26052, 27705 => 26051, 27706 => 26060, 27707 => 26062, 27708 => 26066, + 27709 => 26070, 27710 => 28800, 27711 => 28828, 27712 => 28822, 27713 => 28829, + 27714 => 28859, 27715 => 28864, 27716 => 28855, 27717 => 28843, 27718 => 28849, + 27719 => 28904, 27720 => 28874, 27721 => 28944, 27722 => 28947, 27723 => 28950, + 27724 => 28975, 27725 => 28977, 27726 => 29043, 27727 => 29020, 27728 => 29032, + 27729 => 28997, 27730 => 29042, 27731 => 29002, 27732 => 29048, 27733 => 29050, + 27734 => 29080, 27735 => 29107, 27736 => 29109, 27737 => 29096, 27738 => 29088, + 27739 => 29152, 27740 => 29140, 27741 => 29159, 27742 => 29177, 27743 => 29213, + 27744 => 29224, 27745 => 28780, 27746 => 28952, 27747 => 29030, 27748 => 29113, + 27749 => 25150, 27750 => 25149, 27751 => 25155, 27752 => 25160, 27753 => 25161, + 27754 => 31035, 27755 => 31040, 27756 => 31046, 27757 => 31049, 27758 => 31067, + 27759 => 31068, 27760 => 31059, 27761 => 31066, 27762 => 31074, 27763 => 31063, + 27764 => 31072, 27765 => 31087, 27766 => 31079, 27767 => 31098, 27768 => 31109, + 27769 => 31114, 27770 => 31130, 27771 => 31143, 27772 => 31155, 27773 => 24529, + 27774 => 24528, 27937 => 24636, 27938 => 24669, 27939 => 24666, 27940 => 24679, + 27941 => 24641, 27942 => 24665, 27943 => 24675, 27944 => 24747, 27945 => 24838, + 27946 => 24845, 27947 => 24925, 27948 => 25001, 27949 => 24989, 27950 => 25035, + 27951 => 25041, 27952 => 25094, 27953 => 32896, 27954 => 32895, 27955 => 27795, + 27956 => 27894, 27957 => 28156, 27958 => 30710, 27959 => 30712, 27960 => 30720, + 27961 => 30729, 27962 => 30743, 27963 => 30744, 27964 => 30737, 27965 => 26027, + 27966 => 30765, 27967 => 30748, 27968 => 30749, 27969 => 30777, 27970 => 30778, + 27971 => 30779, 27972 => 30751, 27973 => 30780, 27974 => 30757, 27975 => 30764, + 27976 => 30755, 27977 => 30761, 27978 => 30798, 27979 => 30829, 27980 => 30806, + 27981 => 30807, 27982 => 30758, 27983 => 30800, 27984 => 30791, 27985 => 30796, + 27986 => 30826, 27987 => 30875, 27988 => 30867, 27989 => 30874, 27990 => 30855, + 27991 => 30876, 27992 => 30881, 27993 => 30883, 27994 => 30898, 27995 => 30905, + 27996 => 30885, 27997 => 30932, 27998 => 30937, 27999 => 30921, 28000 => 30956, + 28001 => 30962, 28002 => 30981, 28003 => 30964, 28004 => 30995, 28005 => 31012, + 28006 => 31006, 28007 => 31028, 28008 => 40859, 28009 => 40697, 28010 => 40699, + 28011 => 40700, 28012 => 30449, 28013 => 30468, 28014 => 30477, 28015 => 30457, + 28016 => 30471, 28017 => 30472, 28018 => 30490, 28019 => 30498, 28020 => 30489, + 28021 => 30509, 28022 => 30502, 28023 => 30517, 28024 => 30520, 28025 => 30544, + 28026 => 30545, 28027 => 30535, 28028 => 30531, 28029 => 30554, 28030 => 30568, + 28193 => 30562, 28194 => 30565, 28195 => 30591, 28196 => 30605, 28197 => 30589, + 28198 => 30592, 28199 => 30604, 28200 => 30609, 28201 => 30623, 28202 => 30624, + 28203 => 30640, 28204 => 30645, 28205 => 30653, 28206 => 30010, 28207 => 30016, + 28208 => 30030, 28209 => 30027, 28210 => 30024, 28211 => 30043, 28212 => 30066, + 28213 => 30073, 28214 => 30083, 28215 => 32600, 28216 => 32609, 28217 => 32607, + 28218 => 35400, 28219 => 32616, 28220 => 32628, 28221 => 32625, 28222 => 32633, + 28223 => 32641, 28224 => 32638, 28225 => 30413, 28226 => 30437, 28227 => 34866, + 28228 => 38021, 28229 => 38022, 28230 => 38023, 28231 => 38027, 28232 => 38026, + 28233 => 38028, 28234 => 38029, 28235 => 38031, 28236 => 38032, 28237 => 38036, + 28238 => 38039, 28239 => 38037, 28240 => 38042, 28241 => 38043, 28242 => 38044, + 28243 => 38051, 28244 => 38052, 28245 => 38059, 28246 => 38058, 28247 => 38061, + 28248 => 38060, 28249 => 38063, 28250 => 38064, 28251 => 38066, 28252 => 38068, + 28253 => 38070, 28254 => 38071, 28255 => 38072, 28256 => 38073, 28257 => 38074, + 28258 => 38076, 28259 => 38077, 28260 => 38079, 28261 => 38084, 28262 => 38088, + 28263 => 38089, 28264 => 38090, 28265 => 38091, 28266 => 38092, 28267 => 38093, + 28268 => 38094, 28269 => 38096, 28270 => 38097, 28271 => 38098, 28272 => 38101, + 28273 => 38102, 28274 => 38103, 28275 => 38105, 28276 => 38104, 28277 => 38107, + 28278 => 38110, 28279 => 38111, 28280 => 38112, 28281 => 38114, 28282 => 38116, + 28283 => 38117, 28284 => 38119, 28285 => 38120, 28286 => 38122, 28449 => 38121, + 28450 => 38123, 28451 => 38126, 28452 => 38127, 28453 => 38131, 28454 => 38132, + 28455 => 38133, 28456 => 38135, 28457 => 38137, 28458 => 38140, 28459 => 38141, + 28460 => 38143, 28461 => 38147, 28462 => 38146, 28463 => 38150, 28464 => 38151, + 28465 => 38153, 28466 => 38154, 28467 => 38157, 28468 => 38158, 28469 => 38159, + 28470 => 38162, 28471 => 38163, 28472 => 38164, 28473 => 38165, 28474 => 38166, + 28475 => 38168, 28476 => 38171, 28477 => 38173, 28478 => 38174, 28479 => 38175, + 28480 => 38178, 28481 => 38186, 28482 => 38187, 28483 => 38185, 28484 => 38188, + 28485 => 38193, 28486 => 38194, 28487 => 38196, 28488 => 38198, 28489 => 38199, + 28490 => 38200, 28491 => 38204, 28492 => 38206, 28493 => 38207, 28494 => 38210, + 28495 => 38197, 28496 => 38212, 28497 => 38213, 28498 => 38214, 28499 => 38217, + 28500 => 38220, 28501 => 38222, 28502 => 38223, 28503 => 38226, 28504 => 38227, + 28505 => 38228, 28506 => 38230, 28507 => 38231, 28508 => 38232, 28509 => 38233, + 28510 => 38235, 28511 => 38238, 28512 => 38239, 28513 => 38237, 28514 => 38241, + 28515 => 38242, 28516 => 38244, 28517 => 38245, 28518 => 38246, 28519 => 38247, + 28520 => 38248, 28521 => 38249, 28522 => 38250, 28523 => 38251, 28524 => 38252, + 28525 => 38255, 28526 => 38257, 28527 => 38258, 28528 => 38259, 28529 => 38202, + 28530 => 30695, 28531 => 30700, 28532 => 38601, 28533 => 31189, 28534 => 31213, + 28535 => 31203, 28536 => 31211, 28537 => 31238, 28538 => 23879, 28539 => 31235, + 28540 => 31234, 28541 => 31262, 28542 => 31252, 28705 => 31289, 28706 => 31287, + 28707 => 31313, 28708 => 40655, 28709 => 39333, 28710 => 31344, 28711 => 30344, + 28712 => 30350, 28713 => 30355, 28714 => 30361, 28715 => 30372, 28716 => 29918, + 28717 => 29920, 28718 => 29996, 28719 => 40480, 28720 => 40482, 28721 => 40488, + 28722 => 40489, 28723 => 40490, 28724 => 40491, 28725 => 40492, 28726 => 40498, + 28727 => 40497, 28728 => 40502, 28729 => 40504, 28730 => 40503, 28731 => 40505, + 28732 => 40506, 28733 => 40510, 28734 => 40513, 28735 => 40514, 28736 => 40516, + 28737 => 40518, 28738 => 40519, 28739 => 40520, 28740 => 40521, 28741 => 40523, + 28742 => 40524, 28743 => 40526, 28744 => 40529, 28745 => 40533, 28746 => 40535, + 28747 => 40538, 28748 => 40539, 28749 => 40540, 28750 => 40542, 28751 => 40547, + 28752 => 40550, 28753 => 40551, 28754 => 40552, 28755 => 40553, 28756 => 40554, + 28757 => 40555, 28758 => 40556, 28759 => 40561, 28760 => 40557, 28761 => 40563, + 28762 => 30098, 28763 => 30100, 28764 => 30102, 28765 => 30112, 28766 => 30109, + 28767 => 30124, 28768 => 30115, 28769 => 30131, 28770 => 30132, 28771 => 30136, + 28772 => 30148, 28773 => 30129, 28774 => 30128, 28775 => 30147, 28776 => 30146, + 28777 => 30166, 28778 => 30157, 28779 => 30179, 28780 => 30184, 28781 => 30182, + 28782 => 30180, 28783 => 30187, 28784 => 30183, 28785 => 30211, 28786 => 30193, + 28787 => 30204, 28788 => 30207, 28789 => 30224, 28790 => 30208, 28791 => 30213, + 28792 => 30220, 28793 => 30231, 28794 => 30218, 28795 => 30245, 28796 => 30232, + 28797 => 30229, 28798 => 30233, 28961 => 30235, 28962 => 30268, 28963 => 30242, + 28964 => 30240, 28965 => 30272, 28966 => 30253, 28967 => 30256, 28968 => 30271, + 28969 => 30261, 28970 => 30275, 28971 => 30270, 28972 => 30259, 28973 => 30285, + 28974 => 30302, 28975 => 30292, 28976 => 30300, 28977 => 30294, 28978 => 30315, + 28979 => 30319, 28980 => 32714, 28981 => 31462, 28982 => 31352, 28983 => 31353, + 28984 => 31360, 28985 => 31366, 28986 => 31368, 28987 => 31381, 28988 => 31398, + 28989 => 31392, 28990 => 31404, 28991 => 31400, 28992 => 31405, 28993 => 31411, + 28994 => 34916, 28995 => 34921, 28996 => 34930, 28997 => 34941, 28998 => 34943, + 28999 => 34946, 29000 => 34978, 29001 => 35014, 29002 => 34999, 29003 => 35004, + 29004 => 35017, 29005 => 35042, 29006 => 35022, 29007 => 35043, 29008 => 35045, + 29009 => 35057, 29010 => 35098, 29011 => 35068, 29012 => 35048, 29013 => 35070, + 29014 => 35056, 29015 => 35105, 29016 => 35097, 29017 => 35091, 29018 => 35099, + 29019 => 35082, 29020 => 35124, 29021 => 35115, 29022 => 35126, 29023 => 35137, + 29024 => 35174, 29025 => 35195, 29026 => 30091, 29027 => 32997, 29028 => 30386, + 29029 => 30388, 29030 => 30684, 29031 => 32786, 29032 => 32788, 29033 => 32790, + 29034 => 32796, 29035 => 32800, 29036 => 32802, 29037 => 32805, 29038 => 32806, + 29039 => 32807, 29040 => 32809, 29041 => 32808, 29042 => 32817, 29043 => 32779, + 29044 => 32821, 29045 => 32835, 29046 => 32838, 29047 => 32845, 29048 => 32850, + 29049 => 32873, 29050 => 32881, 29051 => 35203, 29052 => 39032, 29053 => 39040, + 29054 => 39043, 29217 => 39049, 29218 => 39052, 29219 => 39053, 29220 => 39055, + 29221 => 39060, 29222 => 39066, 29223 => 39067, 29224 => 39070, 29225 => 39071, + 29226 => 39073, 29227 => 39074, 29228 => 39077, 29229 => 39078, 29230 => 34381, + 29231 => 34388, 29232 => 34412, 29233 => 34414, 29234 => 34431, 29235 => 34426, + 29236 => 34428, 29237 => 34427, 29238 => 34472, 29239 => 34445, 29240 => 34443, + 29241 => 34476, 29242 => 34461, 29243 => 34471, 29244 => 34467, 29245 => 34474, + 29246 => 34451, 29247 => 34473, 29248 => 34486, 29249 => 34500, 29250 => 34485, + 29251 => 34510, 29252 => 34480, 29253 => 34490, 29254 => 34481, 29255 => 34479, + 29256 => 34505, 29257 => 34511, 29258 => 34484, 29259 => 34537, 29260 => 34545, + 29261 => 34546, 29262 => 34541, 29263 => 34547, 29264 => 34512, 29265 => 34579, + 29266 => 34526, 29267 => 34548, 29268 => 34527, 29269 => 34520, 29270 => 34513, + 29271 => 34563, 29272 => 34567, 29273 => 34552, 29274 => 34568, 29275 => 34570, + 29276 => 34573, 29277 => 34569, 29278 => 34595, 29279 => 34619, 29280 => 34590, + 29281 => 34597, 29282 => 34606, 29283 => 34586, 29284 => 34622, 29285 => 34632, + 29286 => 34612, 29287 => 34609, 29288 => 34601, 29289 => 34615, 29290 => 34623, + 29291 => 34690, 29292 => 34594, 29293 => 34685, 29294 => 34686, 29295 => 34683, + 29296 => 34656, 29297 => 34672, 29298 => 34636, 29299 => 34670, 29300 => 34699, + 29301 => 34643, 29302 => 34659, 29303 => 34684, 29304 => 34660, 29305 => 34649, + 29306 => 34661, 29307 => 34707, 29308 => 34735, 29309 => 34728, 29310 => 34770, + 29473 => 34758, 29474 => 34696, 29475 => 34693, 29476 => 34733, 29477 => 34711, + 29478 => 34691, 29479 => 34731, 29480 => 34789, 29481 => 34732, 29482 => 34741, + 29483 => 34739, 29484 => 34763, 29485 => 34771, 29486 => 34749, 29487 => 34769, + 29488 => 34752, 29489 => 34762, 29490 => 34779, 29491 => 34794, 29492 => 34784, + 29493 => 34798, 29494 => 34838, 29495 => 34835, 29496 => 34814, 29497 => 34826, + 29498 => 34843, 29499 => 34849, 29500 => 34873, 29501 => 34876, 29502 => 32566, + 29503 => 32578, 29504 => 32580, 29505 => 32581, 29506 => 33296, 29507 => 31482, + 29508 => 31485, 29509 => 31496, 29510 => 31491, 29511 => 31492, 29512 => 31509, + 29513 => 31498, 29514 => 31531, 29515 => 31503, 29516 => 31559, 29517 => 31544, + 29518 => 31530, 29519 => 31513, 29520 => 31534, 29521 => 31537, 29522 => 31520, + 29523 => 31525, 29524 => 31524, 29525 => 31539, 29526 => 31550, 29527 => 31518, + 29528 => 31576, 29529 => 31578, 29530 => 31557, 29531 => 31605, 29532 => 31564, + 29533 => 31581, 29534 => 31584, 29535 => 31598, 29536 => 31611, 29537 => 31586, + 29538 => 31602, 29539 => 31601, 29540 => 31632, 29541 => 31654, 29542 => 31655, + 29543 => 31672, 29544 => 31660, 29545 => 31645, 29546 => 31656, 29547 => 31621, + 29548 => 31658, 29549 => 31644, 29550 => 31650, 29551 => 31659, 29552 => 31668, + 29553 => 31697, 29554 => 31681, 29555 => 31692, 29556 => 31709, 29557 => 31706, + 29558 => 31717, 29559 => 31718, 29560 => 31722, 29561 => 31756, 29562 => 31742, + 29563 => 31740, 29564 => 31759, 29565 => 31766, 29566 => 31755, 29729 => 31775, + 29730 => 31786, 29731 => 31782, 29732 => 31800, 29733 => 31809, 29734 => 31808, + 29735 => 33278, 29736 => 33281, 29737 => 33282, 29738 => 33284, 29739 => 33260, + 29740 => 34884, 29741 => 33313, 29742 => 33314, 29743 => 33315, 29744 => 33325, + 29745 => 33327, 29746 => 33320, 29747 => 33323, 29748 => 33336, 29749 => 33339, + 29750 => 33331, 29751 => 33332, 29752 => 33342, 29753 => 33348, 29754 => 33353, + 29755 => 33355, 29756 => 33359, 29757 => 33370, 29758 => 33375, 29759 => 33384, + 29760 => 34942, 29761 => 34949, 29762 => 34952, 29763 => 35032, 29764 => 35039, + 29765 => 35166, 29766 => 32669, 29767 => 32671, 29768 => 32679, 29769 => 32687, + 29770 => 32688, 29771 => 32690, 29772 => 31868, 29773 => 25929, 29774 => 31889, + 29775 => 31901, 29776 => 31900, 29777 => 31902, 29778 => 31906, 29779 => 31922, + 29780 => 31932, 29781 => 31933, 29782 => 31937, 29783 => 31943, 29784 => 31948, + 29785 => 31949, 29786 => 31944, 29787 => 31941, 29788 => 31959, 29789 => 31976, + 29790 => 33390, 29791 => 26280, 29792 => 32703, 29793 => 32718, 29794 => 32725, + 29795 => 32741, 29796 => 32737, 29797 => 32742, 29798 => 32745, 29799 => 32750, + 29800 => 32755, 29801 => 31992, 29802 => 32119, 29803 => 32166, 29804 => 32174, + 29805 => 32327, 29806 => 32411, 29807 => 40632, 29808 => 40628, 29809 => 36211, + 29810 => 36228, 29811 => 36244, 29812 => 36241, 29813 => 36273, 29814 => 36199, + 29815 => 36205, 29816 => 35911, 29817 => 35913, 29818 => 37194, 29819 => 37200, + 29820 => 37198, 29821 => 37199, 29822 => 37220, 29985 => 37218, 29986 => 37217, + 29987 => 37232, 29988 => 37225, 29989 => 37231, 29990 => 37245, 29991 => 37246, + 29992 => 37234, 29993 => 37236, 29994 => 37241, 29995 => 37260, 29996 => 37253, + 29997 => 37264, 29998 => 37261, 29999 => 37265, 30000 => 37282, 30001 => 37283, + 30002 => 37290, 30003 => 37293, 30004 => 37294, 30005 => 37295, 30006 => 37301, + 30007 => 37300, 30008 => 37306, 30009 => 35925, 30010 => 40574, 30011 => 36280, + 30012 => 36331, 30013 => 36357, 30014 => 36441, 30015 => 36457, 30016 => 36277, + 30017 => 36287, 30018 => 36284, 30019 => 36282, 30020 => 36292, 30021 => 36310, + 30022 => 36311, 30023 => 36314, 30024 => 36318, 30025 => 36302, 30026 => 36303, + 30027 => 36315, 30028 => 36294, 30029 => 36332, 30030 => 36343, 30031 => 36344, + 30032 => 36323, 30033 => 36345, 30034 => 36347, 30035 => 36324, 30036 => 36361, + 30037 => 36349, 30038 => 36372, 30039 => 36381, 30040 => 36383, 30041 => 36396, + 30042 => 36398, 30043 => 36387, 30044 => 36399, 30045 => 36410, 30046 => 36416, + 30047 => 36409, 30048 => 36405, 30049 => 36413, 30050 => 36401, 30051 => 36425, + 30052 => 36417, 30053 => 36418, 30054 => 36433, 30055 => 36434, 30056 => 36426, + 30057 => 36464, 30058 => 36470, 30059 => 36476, 30060 => 36463, 30061 => 36468, + 30062 => 36485, 30063 => 36495, 30064 => 36500, 30065 => 36496, 30066 => 36508, + 30067 => 36510, 30068 => 35960, 30069 => 35970, 30070 => 35978, 30071 => 35973, + 30072 => 35992, 30073 => 35988, 30074 => 26011, 30075 => 35286, 30076 => 35294, + 30077 => 35290, 30078 => 35292, 30241 => 35301, 30242 => 35307, 30243 => 35311, + 30244 => 35390, 30245 => 35622, 30246 => 38739, 30247 => 38633, 30248 => 38643, + 30249 => 38639, 30250 => 38662, 30251 => 38657, 30252 => 38664, 30253 => 38671, + 30254 => 38670, 30255 => 38698, 30256 => 38701, 30257 => 38704, 30258 => 38718, + 30259 => 40832, 30260 => 40835, 30261 => 40837, 30262 => 40838, 30263 => 40839, + 30264 => 40840, 30265 => 40841, 30266 => 40842, 30267 => 40844, 30268 => 40702, + 30269 => 40715, 30270 => 40717, 30271 => 38585, 30272 => 38588, 30273 => 38589, + 30274 => 38606, 30275 => 38610, 30276 => 30655, 30277 => 38624, 30278 => 37518, + 30279 => 37550, 30280 => 37576, 30281 => 37694, 30282 => 37738, 30283 => 37834, + 30284 => 37775, 30285 => 37950, 30286 => 37995, 30287 => 40063, 30288 => 40066, + 30289 => 40069, 30290 => 40070, 30291 => 40071, 30292 => 40072, 30293 => 31267, + 30294 => 40075, 30295 => 40078, 30296 => 40080, 30297 => 40081, 30298 => 40082, + 30299 => 40084, 30300 => 40085, 30301 => 40090, 30302 => 40091, 30303 => 40094, + 30304 => 40095, 30305 => 40096, 30306 => 40097, 30307 => 40098, 30308 => 40099, + 30309 => 40101, 30310 => 40102, 30311 => 40103, 30312 => 40104, 30313 => 40105, + 30314 => 40107, 30315 => 40109, 30316 => 40110, 30317 => 40112, 30318 => 40113, + 30319 => 40114, 30320 => 40115, 30321 => 40116, 30322 => 40117, 30323 => 40118, + 30324 => 40119, 30325 => 40122, 30326 => 40123, 30327 => 40124, 30328 => 40125, + 30329 => 40132, 30330 => 40133, 30331 => 40134, 30332 => 40135, 30333 => 40138, + 30334 => 40139, 30497 => 40140, 30498 => 40141, 30499 => 40142, 30500 => 40143, + 30501 => 40144, 30502 => 40147, 30503 => 40148, 30504 => 40149, 30505 => 40151, + 30506 => 40152, 30507 => 40153, 30508 => 40156, 30509 => 40157, 30510 => 40159, + 30511 => 40162, 30512 => 38780, 30513 => 38789, 30514 => 38801, 30515 => 38802, + 30516 => 38804, 30517 => 38831, 30518 => 38827, 30519 => 38819, 30520 => 38834, + 30521 => 38836, 30522 => 39601, 30523 => 39600, 30524 => 39607, 30525 => 40536, + 30526 => 39606, 30527 => 39610, 30528 => 39612, 30529 => 39617, 30530 => 39616, + 30531 => 39621, 30532 => 39618, 30533 => 39627, 30534 => 39628, 30535 => 39633, + 30536 => 39749, 30537 => 39747, 30538 => 39751, 30539 => 39753, 30540 => 39752, + 30541 => 39757, 30542 => 39761, 30543 => 39144, 30544 => 39181, 30545 => 39214, + 30546 => 39253, 30547 => 39252, 30548 => 39647, 30549 => 39649, 30550 => 39654, + 30551 => 39663, 30552 => 39659, 30553 => 39675, 30554 => 39661, 30555 => 39673, + 30556 => 39688, 30557 => 39695, 30558 => 39699, 30559 => 39711, 30560 => 39715, + 30561 => 40637, 30562 => 40638, 30563 => 32315, 30564 => 40578, 30565 => 40583, + 30566 => 40584, 30567 => 40587, 30568 => 40594, 30569 => 37846, 30570 => 40605, + 30571 => 40607, 30572 => 40667, 30573 => 40668, 30574 => 40669, 30575 => 40672, + 30576 => 40671, 30577 => 40674, 30578 => 40681, 30579 => 40679, 30580 => 40677, + 30581 => 40682, 30582 => 40687, 30583 => 40738, 30584 => 40748, 30585 => 40751, + 30586 => 40761, 30587 => 40759, 30588 => 40765, 30589 => 40766, 30590 => 40772, + 0 => 0 ); + + function gb2utf8($gb) { + if( !trim($gb) ) return $gb; + $utf8=''; + while($gb) { + if( ord(substr($gb,0,1)) > 127 ) { + $t=substr($gb,0,2); + $gb=substr($gb,2); + $utf8 .= $this->u2utf8($this->codetable[hexdec(bin2hex($t))-0x8080]); + } + else { + $t=substr($gb,0,1); + $gb=substr($gb,1); + $utf8 .= $this->u2utf8($t); + } + } + return $utf8; + } + + function u2utf8($c) { + $str=''; + if ($c < 0x80) { + $str.=$c; + } + else if ($c < 0x800) { + $str.=chr(0xC0 | $c>>6); + $str.=chr(0x80 | $c & 0x3F); + } + else if ($c < 0x10000) { + $str.=chr(0xE0 | $c>>12); + $str.=chr(0x80 | $c>>6 & 0x3F); + $str.=chr(0x80 | $c & 0x3F); + } + else if ($c < 0x200000) { + $str.=chr(0xF0 | $c>>18); + $str.=chr(0x80 | $c>>12 & 0x3F); + $str.=chr(0x80 | $c>>6 & 0x3F); + $str.=chr(0x80 | $c & 0x3F); + } + return $str; + } + +} // END Class + +?> diff --git a/src/classes/jpgraph/jpgraph_gradient.php b/src/classes/jpgraph/jpgraph_gradient.php index a990b9f..225cf60 100644 --- a/src/classes/jpgraph/jpgraph_gradient.php +++ b/src/classes/jpgraph/jpgraph_gradient.php @@ -5,7 +5,7 @@ // Created: 2003-02-01 // Ver: $Id: jpgraph_gradient.php 1761 2009-08-01 08:31:28Z ljp $ // - // Copyright (c) Aditus Consulting. All rights reserved. + // Copyright (c) Asial Corporation. All rights reserved. //======================================================================== */ diff --git a/src/classes/jpgraph/jpgraph_iconplot.php b/src/classes/jpgraph/jpgraph_iconplot.php new file mode 100644 index 0000000..584f801 --- /dev/null +++ b/src/classes/jpgraph/jpgraph_iconplot.php @@ -0,0 +1,190 @@ +iFile = $aFile; + $this->iX=$aX; + $this->iY=$aY; + $this->iScale= $aScale; + if( $aMix < 0 || $aMix > 100 ) { + JpGraphError::RaiseL(8001); //('Mix value for icon must be between 0 and 100.'); + } + $this->iMix = $aMix ; + } + + function SetCountryFlag($aFlag,$aX=0,$aY=0,$aScale=1.0,$aMix=100,$aStdSize=3) { + $this->iCountryFlag = $aFlag; + $this->iX=$aX; + $this->iY=$aY; + $this->iScale= $aScale; + if( $aMix < 0 || $aMix > 100 ) { + JpGraphError::RaiseL(8001);//'Mix value for icon must be between 0 and 100.'); + } + $this->iMix = $aMix; + $this->iCountryStdSize = $aStdSize; + } + + function SetPos($aX,$aY) { + $this->iX=$aX; + $this->iY=$aY; + } + + function CreateFromString($aStr) { + $this->iImgString = $aStr; + } + + function SetScalePos($aX,$aY) { + $this->iScalePosX = $aX; + $this->iScalePosY = $aY; + } + + function SetScale($aScale) { + $this->iScale = $aScale; + } + + function SetMix($aMix) { + if( $aMix < 0 || $aMix > 100 ) { + JpGraphError::RaiseL(8001);//('Mix value for icon must be between 0 and 100.'); + } + $this->iMix = $aMix ; + } + + function SetAnchor($aXAnchor='left',$aYAnchor='center') { + if( !in_array($aXAnchor,$this->iAnchors) || + !in_array($aYAnchor,$this->iAnchors) ) { + JpGraphError::RaiseL(8002);//("Anchor position for icons must be one of 'top', 'bottom', 'left', 'right' or 'center'"); + } + $this->iHorAnchor=$aXAnchor; + $this->iVertAnchor=$aYAnchor; + } + + function PreStrokeAdjust($aGraph) { + // Nothing to do ... + } + + function DoLegend($aGraph) { + // Nothing to do ... + } + + function Max() { + return array(false,false); + } + + + // The next four function are framework function tht gets called + // from Gantt and is not menaiungfull in the context of Icons but + // they must be implemented to avoid errors. + function GetMaxDate() { return false; } + function GetMinDate() { return false; } + function GetLineNbr() { return 0; } + function GetAbsHeight() {return 0; } + + + function Min() { + return array(false,false); + } + + function StrokeMargin(&$aImg) { + return true; + } + + function Stroke($aImg,$axscale=null,$ayscale=null) { + $this->StrokeWithScale($aImg,$axscale,$ayscale); + } + + function StrokeWithScale($aImg,$axscale,$ayscale) { + if( $this->iScalePosX === null || $this->iScalePosY === null || + $axscale === null || $ayscale === null ) { + $this->_Stroke($aImg); + } + else { + $this->_Stroke($aImg, + round($axscale->Translate($this->iScalePosX)), + round($ayscale->Translate($this->iScalePosY))); + } + } + + function GetWidthHeight() { + $dummy=0; + return $this->_Stroke($dummy,null,null,true); + } + + function _Stroke($aImg,$x=null,$y=null,$aReturnWidthHeight=false) { + if( $this->iFile != '' && $this->iCountryFlag != '' ) { + JpGraphError::RaiseL(8003);//('It is not possible to specify both an image file and a country flag for the same icon.'); + } + if( $this->iFile != '' ) { + $gdimg = Graph::LoadBkgImage('',$this->iFile); + } + elseif( $this->iImgString != '') { + $gdimg = Image::CreateFromString($this->iImgString); + } + + else { + if( ! class_exists('FlagImages',false) ) { + JpGraphError::RaiseL(8004);//('In order to use Country flags as icons you must include the "jpgraph_flags.php" file.'); + } + $fobj = new FlagImages($this->iCountryStdSize); + $dummy=''; + $gdimg = $fobj->GetImgByName($this->iCountryFlag,$dummy); + } + + $iconw = imagesx($gdimg); + $iconh = imagesy($gdimg); + + if( $aReturnWidthHeight ) { + return array(round($iconw*$this->iScale),round($iconh*$this->iScale)); + } + + if( $x !== null && $y !== null ) { + $this->iX = $x; $this->iY = $y; + } + if( $this->iX >= 0 && $this->iX <= 1.0 ) { + $w = imagesx($aImg->img); + $this->iX = round($w*$this->iX); + } + if( $this->iY >= 0 && $this->iY <= 1.0 ) { + $h = imagesy($aImg->img); + $this->iY = round($h*$this->iY); + } + + if( $this->iHorAnchor == 'center' ) + $this->iX -= round($iconw*$this->iScale/2); + if( $this->iHorAnchor == 'right' ) + $this->iX -= round($iconw*$this->iScale); + if( $this->iVertAnchor == 'center' ) + $this->iY -= round($iconh*$this->iScale/2); + if( $this->iVertAnchor == 'bottom' ) + $this->iY -= round($iconh*$this->iScale); + + $aImg->CopyMerge($gdimg,$this->iX,$this->iY,0,0, + round($iconw*$this->iScale),round($iconh*$this->iScale), + $iconw,$iconh, + $this->iMix); + } +} + +?> diff --git a/src/classes/jpgraph/jpgraph_imgtrans.php b/src/classes/jpgraph/jpgraph_imgtrans.php new file mode 100644 index 0000000..411a781 --- /dev/null +++ b/src/classes/jpgraph/jpgraph_imgtrans.php @@ -0,0 +1,223 @@ +gdImg = $aGdImg; + } + + // -------------------------------------------------------------------- + // _TransVert3D() and _TransHor3D() are helper methods to + // Skew3D(). + // -------------------------------------------------------------------- + function _TransVert3D($aGdImg,$aHorizon=100,$aSkewDist=120,$aDir=SKEW3D_DOWN,$aMinSize=true,$aFillColor='#FFFFFF',$aQuality=false,$aBorder=false,$aHorizonPos=0.5) { + + + // Parameter check + if( $aHorizonPos < 0 || $aHorizonPos > 1.0 ) { + JpGraphError::RaiseL(9001); + //("Value for image transformation out of bounds.\nVanishing point on horizon must be specified as a value between 0 and 1."); + } + + $w = imagesx($aGdImg); + $h = imagesy($aGdImg); + + // Create new image + $ww = $w; + if( $aMinSize ) + $hh = ceil($h * $aHorizon / ($aSkewDist+$h)); + else + $hh = $h; + + $newgdh = imagecreatetruecolor($ww,$hh); + $crgb = new RGB( $newgdh ); + $fillColor = $crgb->Allocate($aFillColor); + imagefilledrectangle($newgdh,0,0,$ww-1,$hh-1,$fillColor); + + if( $aBorder ) { + $colidx = $crgb->Allocate($aBorder); + imagerectangle($newgdh,0,0,$ww-1,$hh-1,$colidx); + } + + $mid = round($w * $aHorizonPos); + + $last=$h; + for($y=0; $y < $h; ++$y) { + + $yp = $h-$y-1; + $yt = floor($yp * $aHorizon / ($aSkewDist + $yp)); + + if( !$aQuality ) { + if( $last <= $yt ) continue ; + $last = $yt; + } + + for($x=0; $x < $w; ++$x) { + $xt = ($x-$mid) * $aSkewDist / ($aSkewDist + $yp); + if( $aDir == SKEW3D_UP ) + $rgb = imagecolorat($aGdImg,$x,$h-$y-1); + else + $rgb = imagecolorat($aGdImg,$x,$y); + $r = ($rgb >> 16) & 0xFF; + $g = ($rgb >> 8) & 0xFF; + $b = $rgb & 0xFF; + $colidx = imagecolorallocate($newgdh,$r,$g,$b); + $xt = round($xt+$mid); + if( $aDir == SKEW3D_UP ) { + $syt = $yt; + } + else { + $syt = $hh-$yt-1; + } + + if( !empty($set[$yt]) ) { + $nrgb = imagecolorat($newgdh,$xt,$syt); + $nr = ($nrgb >> 16) & 0xFF; + $ng = ($nrgb >> 8) & 0xFF; + $nb = $nrgb & 0xFF; + $colidx = imagecolorallocate($newgdh,floor(($r+$nr)/2), + floor(($g+$ng)/2),floor(($b+$nb)/2)); + } + + imagesetpixel($newgdh,$xt,$syt,$colidx); + } + + $set[$yt] = true; + } + + return $newgdh; + } + + // -------------------------------------------------------------------- + // _TransVert3D() and _TransHor3D() are helper methods to + // Skew3D(). + // -------------------------------------------------------------------- + function _TransHor3D($aGdImg,$aHorizon=100,$aSkewDist=120,$aDir=SKEW3D_LEFT,$aMinSize=true,$aFillColor='#FFFFFF',$aQuality=false,$aBorder=false,$aHorizonPos=0.5) { + + $w = imagesx($aGdImg); + $h = imagesy($aGdImg); + + // Create new image + $hh = $h; + if( $aMinSize ) + $ww = ceil($w * $aHorizon / ($aSkewDist+$w)); + else + $ww = $w; + + $newgdh = imagecreatetruecolor($ww,$hh); + $crgb = new RGB( $newgdh ); + $fillColor = $crgb->Allocate($aFillColor); + imagefilledrectangle($newgdh,0,0,$ww-1,$hh-1,$fillColor); + + if( $aBorder ) { + $colidx = $crgb->Allocate($aBorder); + imagerectangle($newgdh,0,0,$ww-1,$hh-1,$colidx); + } + + $mid = round($h * $aHorizonPos); + + $last = -1; + for($x=0; $x < $w-1; ++$x) { + $xt = floor($x * $aHorizon / ($aSkewDist + $x)); + if( !$aQuality ) { + if( $last >= $xt ) continue ; + $last = $xt; + } + + for($y=0; $y < $h; ++$y) { + $yp = $h-$y-1; + $yt = ($yp-$mid) * $aSkewDist / ($aSkewDist + $x); + + if( $aDir == SKEW3D_RIGHT ) + $rgb = imagecolorat($aGdImg,$w-$x-1,$y); + else + $rgb = imagecolorat($aGdImg,$x,$y); + $r = ($rgb >> 16) & 0xFF; + $g = ($rgb >> 8) & 0xFF; + $b = $rgb & 0xFF; + $colidx = imagecolorallocate($newgdh,$r,$g,$b); + $yt = floor($hh-$yt-$mid-1); + if( $aDir == SKEW3D_RIGHT ) { + $sxt = $ww-$xt-1; + } + else + $sxt = $xt ; + + if( !empty($set[$xt]) ) { + $nrgb = imagecolorat($newgdh,$sxt,$yt); + $nr = ($nrgb >> 16) & 0xFF; + $ng = ($nrgb >> 8) & 0xFF; + $nb = $nrgb & 0xFF; + $colidx = imagecolorallocate($newgdh,floor(($r+$nr)/2), + floor(($g+$ng)/2),floor(($b+$nb)/2)); + } + imagesetpixel($newgdh,$sxt,$yt,$colidx); + } + + $set[$xt] = true; + } + + return $newgdh; + } + + // -------------------------------------------------------------------- + // Skew image for the apperance of a 3D effect + // This transforms an image into a 3D-skewed version + // of the image. The transformation is specified by giving the height + // of the artificial horizon and specifying a "skew" factor which + // is the distance on the horizon line between the point of + // convergence and perspective line. + // + // The function returns the GD handle of the transformed image + // leaving the original image untouched. + // + // Parameters: + // * $aGdImg, GD handle to the image to be transformed + // * $aHorizon, Distance to the horizon + // * $aSkewDist, Distance from the horizon point of convergence + // on the horizon line to the perspective points. A larger + // value will fore-shorten the image more + // * $aDir, parameter specifies type of convergence. This of this + // as the walls in a room you are looking at. This specifies if the + // image should be applied on the left,right,top or bottom walls. + // * $aMinSize, true=make the new image just as big as needed, + // false = keep the image the same size as the original image + // * $aFillColor, Background fill color in the image + // * $aHiQuality, true=performa some interpolation that improves + // the image quality but at the expense of performace. Enabling + // high quality will have a dramatic effect on the time it takes + // to transform an image. + // * $aBorder, if set to anything besides false this will draw a + // a border of the speciied color around the image + // -------------------------------------------------------------------- + function Skew3D($aHorizon=120,$aSkewDist=150,$aDir=SKEW3D_DOWN,$aHiQuality=false,$aMinSize=true,$aFillColor='#FFFFFF',$aBorder=false) { + return $this->_Skew3D($this->gdImg,$aHorizon,$aSkewDist,$aDir,$aHiQuality, + $aMinSize,$aFillColor,$aBorder); + } + + function _Skew3D($aGdImg,$aHorizon=120,$aSkewDist=150,$aDir=SKEW3D_DOWN,$aHiQuality=false,$aMinSize=true,$aFillColor='#FFFFFF',$aBorder=false) { + if( $aDir == SKEW3D_DOWN || $aDir == SKEW3D_UP ) + return $this->_TransVert3D($aGdImg,$aHorizon,$aSkewDist,$aDir,$aMinSize,$aFillColor,$aHiQuality,$aBorder); + else + return $this->_TransHor3D($aGdImg,$aHorizon,$aSkewDist,$aDir,$aMinSize,$aFillColor,$aHiQuality,$aBorder); + + } + +} + + +?> diff --git a/src/classes/jpgraph/jpgraph_led.php b/src/classes/jpgraph/jpgraph_led.php new file mode 100644 index 0000000..83bb269 --- /dev/null +++ b/src/classes/jpgraph/jpgraph_led.php @@ -0,0 +1,311 @@ + array('red','darkred:0.9','red:0.3'),// 0 + LEDC_GREEN => array('green','darkgreen','green:0.3'),// 1 + LEDC_BLUE => array('lightblue:0.9','darkblue:0.85','darkblue:0.7'),// 2 + LEDC_YELLOW => array('yellow','yellow:0.4','yellow:0.3'),// 3 + LEDC_GRAY => array('gray:1.4','darkgray:0.85','darkgray:0.7'), + LEDC_CHOCOLATE => array('chocolate','chocolate:0.7','chocolate:0.5'), + LEDC_PERU => array('peru:0.95','peru:0.6','peru:0.5'), + LEDC_GOLDENROD => array('goldenrod','goldenrod:0.6','goldenrod:0.5'), + LEDC_KHAKI => array('khaki:0.7','khaki:0.4','khaki:0.3'), + LEDC_OLIVE => array('#808000','#808000:0.7','#808000:0.6'), + LEDC_LIMEGREEN => array('limegreen:0.9','limegreen:0.5','limegreen:0.4'), + LEDC_FORESTGREEN => array('forestgreen','forestgreen:0.7','forestgreen:0.5'), + LEDC_TEAL => array('teal','teal:0.7','teal:0.5'), + LEDC_STEELBLUE => array('steelblue','steelblue:0.65','steelblue:0.5'), + LEDC_NAVY => array('navy:1.3','navy:0.95','navy:0.8'),//14 + LEDC_INVERTGRAY => array('darkgray','lightgray:1.5','white')//15 + ), + + /* Each line of the character is encoded as a 4 bit value + 0 ____ + 1 ___x + 2 __x_ + 3 __xx + 4 _x__ + 5 _x_x + 6 _xx_ + 7 _xxx + 8 x___ + 9 x__x + 10 x_x_ + 11 x_xx + 12 xx__ + 13 xx_x + 14 xxx_ + 15 xxxx + */ + + $iLEDSpec = array( + 0 => array(6,9,11,15,13,9,6), + 1 => array(2,6,10,2,2,2,2), + 2 => array(6,9,1,2,4,8,15), + 3 => array(6,9,1,6,1,9,6), + 4 => array(1,3,5,9,15,1,1), + 5 => array(15,8,8,14,1,9,6), + 6 => array(6,8,8,14,9,9,6), + 7 => array(15,1,1,2,4,4,4), + 8 => array(6,9,9,6,9,9,6), + 9 => array(6,9,9,7,1,1,6), + '!' => array(4,4,4,4,4,0,4), + '?' => array(6,9,1,2,2,0,2), + '#' => array(0,9,15,9,15,9,0), + '@' => array(6,9,11,11,10,9,6), + '-' => array(0,0,0,15,0,0,0), + '_' => array(0,0,0,0,0,0,15), + '=' => array(0,0,15,0,15,0,0), + '+' => array(0,0,4,14,4,0,0), + '|' => array(4,4,4,4,4,4,4), //vertical line, used for simulate rus 'Ы' + ',' => array(0,0,0,0,0,12,4), + '.' => array(0,0,0,0,0,12,12), + ':' => array(12,12,0,0,0,12,12), + ';' => array(12,12,0,0,0,12,4), + '[' => array(3,2,2,2,2,2,3), + ']' => array(12,4,4,4,4,4,12), + '(' => array(1,2,2,2,2,2,1), + ')' => array(8,4,4,4,4,4,8), + '{' => array(3,2,2,6,2,2,3), + '}' => array(12,4,4,6,4,4,12), + '<' => array(1,2,4,8,4,2,1), + '>' => array(8,4,2,1,2,4,8), + '*' => array(9,6,15,6,9,0,0), + '"' => array(10,10,0,0,0,0,0), + '\'' => array(4,4,0,0,0,0,0), + '`' => array(4,2,0,0,0,0,0), + '~' => array(13,11,0,0,0,0,0), + '^' => array(4,10,0,0,0,0,0), + '\\' => array(8,8,4,6,2,1,1), + '/' => array(1,1,2,6,4,8,8), + '%' => array(1,9,2,6,4,9,8), + '&' => array(0,4,10,4,11,10,5), + '$' => array(2,7,8,6,1,14,4), + ' ' => array(0,0,0,0,0,0,0), + '•' => array(0,0,6,6,0,0,0), //149 + '°' => array(14,10,14,0,0,0,0), //176 + '†' => array(4,4,14,4,4,4,4), //134 + '‡' => array(4,4,14,4,14,4,4), //135 + '±' => array(0,4,14,4,0,14,0), //177 + '‰' => array(0,4,2,15,2,4,0), //137 show right arrow + '™' => array(0,2,4,15,4,2,0), //156 show left arrow + 'Ў' => array(0,0,8,8,0,0,0), //159 show small hi-stick - that need for simulate rus 'Ф' + "\t" => array(8,8,8,0,0,0,0), //show hi-stick - that need for simulate rus 'У' + "\r" => array(8,8,8,8,8,8,8), //vertical line - that need for simulate 'M', 'W' and rus 'М','Ш' ,'Щ' + "\n" => array(15,15,15,15,15,15,15), //fill up - that need for simulate rus 'Ж' + "Ґ" => array(10,5,10,5,10,5,10), //chess + "µ" => array(15,0,15,0,15,0,15), //4 horizontal lines + // latin + 'A' => array(6,9,9,15,9,9,9), + 'B' => array(14,9,9,14,9,9,14), + 'C' => array(6,9,8,8,8,9,6), + 'D' => array(14,9,9,9,9,9,14), + 'E' => array(15,8,8,14,8,8,15), + 'F' => array(15,8,8,14,8,8,8), + 'G' => array(6,9,8,8,11,9,6), + 'H' => array(9,9,9,15,9,9,9), + 'I' => array(14,4,4,4,4,4,14), + 'J' => array(15,1,1,1,1,9,6), + 'K' => array(8,9,10,12,12,10,9), + 'L' => array(8,8,8,8,8,8,15), + 'M' => array(8,13,10,8,8,8,8),// need to add \r + 'N' => array(9,9,13,11,9,9,9), + 'O' => array(6,9,9,9,9,9,6), + 'P' => array(14,9,9,14,8,8,8), + 'Q' => array(6,9,9,9,13,11,6), + 'R' => array(14,9,9,14,12,10,9), + 'S' => array(6,9,8,6,1,9,6), + 'T' => array(14,4,4,4,4,4,4), + 'U' => array(9,9,9,9,9,9,6), + 'V' => array(0,0,0,10,10,10,4), + 'W' => array(8,8,8,8,10,13,8),// need to add \r + 'X' => array(9,9,6,6,6,9,9), + 'Y' => array(10,10,10,10,4,4,4), + 'Z' => array(15,1,2,6,4,8,15), + // russian utf-8 + 'А' => array(6,9,9,15,9,9,9), + 'Б' => array(14,8,8,14,9,9,14), + 'В' => array(14,9,9,14,9,9,14), + 'Г' => array(15,8,8,8,8,8,8), + 'Д' => array(14,9,9,9,9,9,14), + 'Е' => array(15,8,8,14,8,8,15), + 'Ё' => array(6,15,8,14,8,8,15), + //Ж is combine: >\n< + 'З' => array(6,9,1,2,1,9,6), + 'И' => array(9,9,9,11,13,9,9), + 'Й' => array(13,9,9,11,13,9,9), + 'К' => array(9,10,12,10,9,9,9), + 'Л' => array(7,9,9,9,9,9,9), + 'М' => array(8,13,10,8,8,8,8),// need to add \r + 'Н' => array(9,9,9,15,9,9,9), + 'О' => array(6,9,9,9,9,9,6), + 'П' => array(15,9,9,9,9,9,9), + 'Р' => array(14,9,9,14,8,8,8), + 'С' => array(6,9,8,8,8,9,6), + 'Т' => array(14,4,4,4,4,4,4), + 'У' => array(9,9,9,7,1,9,6), + 'Ф' => array(2,7,10,10,7,2,2),// need to add Ў + 'Х' => array(9,9,6,6,6,9,9), + 'Ц' => array(10,10,10,10,10,15,1), + 'Ч' => array(9,9,9,7,1,1,1), + 'Ш' => array(10,10,10,10,10,10,15),// \r + 'Щ' => array(10,10,10,10,10,15,0),// need to add \r + 'Ъ' => array(12,4,4,6,5,5,6), + 'Ы' => array(8,8,8,14,9,9,14),// need to add | + 'Ь' => array(8,8,8,14,9,9,14), + 'Э' => array(6,9,1,7,1,9,6), + 'Ю' => array(2,2,2,3,2,2,2),// need to add O + 'Я' => array(7,9,9,7,3,5,9) + ), + + $iSuperSampling = 3, $iMarg = 1, $iRad = 4; + + function __construct($aRadius = 2, $aMargin= 0.6) { + $this->iRad = $aRadius; + $this->iMarg = $aMargin; + } + + function SetSupersampling($aSuperSampling = 2) { + $this->iSuperSampling = $aSuperSampling; + } + + function _GetLED($aLedIdx, $aColor = 0) { + $width= $this->iLED_X*$this->iRad*2 + ($this->iLED_X+1)*$this->iMarg + $this->iRad ; + $height= $this->iLED_Y*$this->iRad*2 + ($this->iLED_Y)*$this->iMarg + $this->iRad * 2; + + // Adjust radious for supersampling + $rad = $this->iRad * $this->iSuperSampling; + + // Margin in between "Led" dots + $marg = $this->iMarg * $this->iSuperSampling; + + $swidth = $width*$this->iSuperSampling; + $sheight = $height*$this->iSuperSampling; + + $simg = new RotImage($swidth, $sheight, 0, DEFAULT_GFORMAT, false); + $simg->SetColor($this->iColorSchema[$aColor][2]); + $simg->FilledRectangle(0, 0, $swidth-1, $sheight-1); + + if( array_key_exists($aLedIdx, $this->iLEDSpec) ) { + $d = $this->iLEDSpec[$aLedIdx]; + } + else { + $d = array(0,0,0,0,0,0,0); + } + + for($r = 0; $r < 7; ++$r) { + $dr = $d[$r]; + for($c = 0; $c < 4; ++$c) { + if( ($dr & pow(2,3-$c)) !== 0 ) { + $color = $this->iColorSchema[$aColor][0]; + } + else { + $color = $this->iColorSchema[$aColor][1]; + } + + $x = 2*$rad*$c+$rad + ($c+1)*$marg + $rad ; + $y = 2*$rad*$r+$rad + ($r+1)*$marg + $rad ; + + $simg->SetColor($color); + $simg->FilledCircle($x,$y,$rad); + } + } + + $img = new Image($width, $height, DEFAULT_GFORMAT, false); + $img->Copy($simg->img, 0, 0, 0, 0, $width, $height, $swidth, $sheight); + $simg->Destroy(); + unset($simg); + return $img; + } + + + function Stroke($aValStr, $aColor = 0, $aFileName = '') { + $this->StrokeNumber($aValStr, $aColor, $aFileName); + } + + + function StrokeNumber($aValStr, $aColor = 0, $aFileName = '') { + if( $aColor < 0 || $aColor >= sizeof($this->iColorSchema) ) { + $aColor = 0; + } + + if(($n = mb_strlen($aValStr,'utf8')) == 0) { + $aValStr = ' '; + $n = 1; + } + + for($i = 0; $i < $n; ++$i) { + $d = mb_substr($aValStr, $i, 1, 'utf8'); + if( ctype_digit($d) ) { + $d = (int)$d; + } + else { + $d = strtoupper($d); + } + $digit_img[$i] = $this->_GetLED($d, $aColor); + } + + $w = imagesx($digit_img[0]->img); + $h = imagesy($digit_img[0]->img); + + $number_img = new Image($w*$n, $h, DEFAULT_GFORMAT, false); + + for($i = 0; $i < $n; ++$i) { + $number_img->Copy($digit_img[$i]->img, $i*$w, 0, 0, 0, $w, $h, $w, $h); + } + + if( $aFileName != '' ) { + $number_img->Stream($aFileName); + } else { + $number_img->Headers(); + $number_img->Stream(); + } + } +} +?> diff --git a/src/classes/jpgraph/jpgraph_legend.inc.php b/src/classes/jpgraph/jpgraph_legend.inc.php index c1099c4..c7f38b5 100644 --- a/src/classes/jpgraph/jpgraph_legend.inc.php +++ b/src/classes/jpgraph/jpgraph_legend.inc.php @@ -7,7 +7,7 @@ // Created: 2001-01-08 (Refactored to separate file 2008-08-01) // Ver: $Id: jpgraph_legend.inc.php 1926 2010-01-11 16:33:07Z ljp $ // -// Copyright (c) Aditus Consulting. All rights reserved. +// Copyright (c) Asial Corporation. All rights reserved. //======================================================================== DEFINE('_DEFAULT_LPM_SIZE',8); // Default Legend Plot Mark size @@ -21,10 +21,10 @@ DEFINE('_DEFAULT_LPM_SIZE',8); // Default Legend Plot Mark size class Legend { public $txtcol=array(); - public $font_family=FF_FONT1,$font_style=FS_NORMAL,$font_size=12; - private $color=array(0,0,0); // Default fram color - private $fill_color=array(235,235,235); // Default fill color - private $shadow=true; // Shadow around legend "box" + public $font_family=FF_DEFAULT,$font_style=FS_NORMAL,$font_size=8; // old. 12 + private $color=array(120,120,120); // Default frame color + private $fill_color=array(245,245,245); // Default fill color + private $shadow=false; // Shadow around legend "box" private $shadow_color='darkgray'; private $mark_abs_hsize=_DEFAULT_LPM_SIZE,$mark_abs_vsize=_DEFAULT_LPM_SIZE; private $xmargin=10,$ymargin=0,$shadow_width=2; @@ -170,6 +170,10 @@ class Legend { $this->bkg_gradto = $aTo; } + function HasItems() { + return (boolean)(count($this->txtcol)); + } + function Stroke($aImg) { // Constant $fillBoxFrameWeight=1; @@ -209,7 +213,7 @@ class Legend { $rows++; $rowheight[$rows-1] = 0; } - $rowheight[$rows-1] = max($rowheight[$rows-1],$h); + $rowheight[$rows-1] = max($rowheight[$rows-1],$h)+1; } $abs_height = 0; @@ -364,6 +368,11 @@ class Legend { $aImg->StyleLine($x1-$this->mark_abs_hsize,$marky,$x1+$this->mark_abs_hsize,$marky); } + // Stroke a mark using image + if( $p[2]->GetType() == MARK_IMG ) { + $p[2]->Stroke($aImg,$x1,$marky); + } + // Stroke a mark with the standard size // (As long as it is not an image mark ) if( $p[2]->GetType() != MARK_IMG ) { @@ -426,9 +435,10 @@ class Legend { } else { $aImg->SetColor($p[1]); - $aImg->FilledRectangle($x1-$boxsize/2,$ym, - $x1+$boxsize/2,$ym+$boxsize); + $aImg->FilledRectangle($x1-$boxsize/2,$ym, $x1+$boxsize/2,$ym+$boxsize); } + + // Draw a plot frame line $aImg->SetColor($this->color); $aImg->SetLineWeight($fillBoxFrameWeight); $aImg->Rectangle($x1-$boxsize/2,$ym, diff --git a/src/classes/jpgraph/jpgraph_line.php b/src/classes/jpgraph/jpgraph_line.php index 3151fb4..3f31b73 100644 --- a/src/classes/jpgraph/jpgraph_line.php +++ b/src/classes/jpgraph/jpgraph_line.php @@ -5,7 +5,7 @@ // Created: 2001-01-08 // Ver: $Id: jpgraph_line.php 1921 2009-12-11 11:46:39Z ljp $ // - // Copyright (c) Aditus Consulting. All rights reserved. + // Copyright (c) Asial Corporation. All rights reserved. //======================================================================== */ @@ -35,11 +35,14 @@ class LinePlot extends Plot{ //--------------- // CONSTRUCTOR - function LinePlot($datay,$datax=false) { + function __construct($datay,$datax=false) { parent::__construct($datay,$datax); $this->mark = new PlotMark() ; $this->color = ColorFactory::getColor(); $this->fill_color = $this->color; + } + function LinePlot($datay,$datax=false) { + self::__construct($datay,$datax); } //--------------- // PUBLIC METHODS diff --git a/src/classes/jpgraph/jpgraph_log.php b/src/classes/jpgraph/jpgraph_log.php new file mode 100644 index 0000000..d5146ec --- /dev/null +++ b/src/classes/jpgraph/jpgraph_log.php @@ -0,0 +1,305 @@ +ticks = new LogTicks(); + $this->name = 'log'; + } + + //---------------- + // PUBLIC METHODS + + // Translate between world and screen + function Translate($a) { + if( !is_numeric($a) ) { + if( $a != '' && $a != '-' && $a != 'x' ) { + JpGraphError::RaiseL(11001); + // ('Your data contains non-numeric values.'); + } + return 1; + } + if( $a < 0 ) { + JpGraphError::RaiseL(11002); + //("Negative data values can not be used in a log scale."); + exit(1); + } + if( $a==0 ) $a=1; + $a=log10($a); + return ceil($this->off + ($a*1.0 - $this->scale[0]) * $this->scale_factor); + } + + // Relative translate (don't include offset) usefull when we just want + // to know the relative position (in pixels) on the axis + function RelTranslate($a) { + if( !is_numeric($a) ) { + if( $a != '' && $a != '-' && $a != 'x' ) { + JpGraphError::RaiseL(11001); + //('Your data contains non-numeric values.'); + } + return 1; + } + if( $a==0 ) { + $a=1; + } + $a=log10($a); + return round(($a*1.0 - $this->scale[0]) * $this->scale_factor); + } + + // Use bcpow() for increased precision + function GetMinVal() { + if( function_exists("bcpow") ) { + return round(bcpow(10,$this->scale[0],15),14); + } + else { + return round(pow(10,$this->scale[0]),14); + } + } + + function GetMaxVal() { + if( function_exists("bcpow") ) { + return round(bcpow(10,$this->scale[1],15),14); + } + else { + return round(pow(10,$this->scale[1]),14); + } + } + + // Logarithmic autoscaling is much simplier since we just + // set the min and max to logs of the min and max values. + // Note that for log autoscale the "maxstep" the fourth argument + // isn't used. This is just included to give the method the same + // signature as the linear counterpart. + function AutoScale($img,$min,$max,$maxsteps,$majend=true) { + if( $min==0 ) $min=1; + + if( $max <= 0 ) { + JpGraphError::RaiseL(11004); + //('Scale error for logarithmic scale. You have a problem with your data values. The max value must be greater than 0. It is mathematically impossible to have 0 in a logarithmic scale.'); + } + if( is_numeric($this->autoscale_min) ) { + $smin = round($this->autoscale_min); + $smax = ceil(log10($max)); + if( $min >= $max ) { + JpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.'); + } + } + else { + $smin = floor(log10($min)); + if( is_numeric($this->autoscale_max) ) { + $smax = round($this->autoscale_max); + if( $smin >= $smax ) { + JpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.'); + } + } + else + $smax = ceil(log10($max)); + } + + $this->Update($img,$smin,$smax); + } + //--------------- + // PRIVATE METHODS +} // Class + +//=================================================== +// CLASS LogTicks +// Description: +//=================================================== +class LogTicks extends Ticks{ + private $label_logtype=LOGLABELS_MAGNITUDE; + private $ticklabels_pos = array(); + //--------------- + // CONSTRUCTOR + function LogTicks() { + } + //--------------- + // PUBLIC METHODS + function IsSpecified() { + return true; + } + + function SetLabelLogType($aType) { + $this->label_logtype = $aType; + } + + // For log scale it's meaningless to speak about a major step + // We just return -1 to make the framework happy (specifically + // StrokeLabels() ) + function GetMajor() { + return -1; + } + + function SetTextLabelStart($aStart) { + JpGraphError::RaiseL(11005); + //('Specifying tick interval for a logarithmic scale is undefined. Remove any calls to SetTextLabelStart() or SetTextTickInterval() on the logarithmic scale.'); + } + + function SetXLabelOffset($dummy) { + // For log scales we dont care about XLabel offset + } + + // Draw ticks on image "img" using scale "scale". The axis absolute + // position in the image is specified in pos, i.e. for an x-axis + // it specifies the absolute y-coord and for Y-ticks it specified the + // absolute x-position. + function Stroke($img,$scale,$pos) { + $start = $scale->GetMinVal(); + $limit = $scale->GetMaxVal(); + $nextMajor = 10*$start; + $step = $nextMajor / 10.0; + + + $img->SetLineWeight($this->weight); + + if( $scale->type == "y" ) { + // member direction specified if the ticks should be on + // left or right side. + $a=$pos + $this->direction*$this->GetMinTickAbsSize(); + $a2=$pos + $this->direction*$this->GetMajTickAbsSize(); + + $count=1; + $this->maj_ticks_pos[0]=$scale->Translate($start); + $this->maj_ticklabels_pos[0]=$scale->Translate($start); + if( $this->supress_first ) + $this->maj_ticks_label[0]=""; + else { + if( $this->label_formfunc != '' ) { + $f = $this->label_formfunc; + $this->maj_ticks_label[0]=call_user_func($f,$start); + } + elseif( $this->label_logtype == LOGLABELS_PLAIN ) { + $this->maj_ticks_label[0]=$start; + } + else { + $this->maj_ticks_label[0]='10^'.round(log10($start)); + } + } + $i=1; + for($y=$start; $y<=$limit; $y+=$step,++$count ) { + $ys=$scale->Translate($y); + $this->ticks_pos[]=$ys; + $this->ticklabels_pos[]=$ys; + if( $count % 10 == 0 ) { + if( !$this->supress_tickmarks ) { + if( $this->majcolor!="" ) { + $img->PushColor($this->majcolor); + $img->Line($pos,$ys,$a2,$ys); + $img->PopColor(); + } + else { + $img->Line($pos,$ys,$a2,$ys); + } + } + + $this->maj_ticks_pos[$i]=$ys; + $this->maj_ticklabels_pos[$i]=$ys; + + if( $this->label_formfunc != '' ) { + $f = $this->label_formfunc; + $this->maj_ticks_label[$i]=call_user_func($f,$nextMajor); + } + elseif( $this->label_logtype == 0 ) { + $this->maj_ticks_label[$i]=$nextMajor; + } + else { + $this->maj_ticks_label[$i]='10^'.round(log10($nextMajor)); + } + ++$i; + $nextMajor *= 10; + $step *= 10; + $count=1; + } + else { + if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { + if( $this->mincolor!="" ) { + $img->PushColor($this->mincolor); + } + $img->Line($pos,$ys,$a,$ys); + if( $this->mincolor!="" ) { + $img->PopColor(); + } + } + } + } + } + else { + $a=$pos - $this->direction*$this->GetMinTickAbsSize(); + $a2=$pos - $this->direction*$this->GetMajTickAbsSize(); + $count=1; + $this->maj_ticks_pos[0]=$scale->Translate($start); + $this->maj_ticklabels_pos[0]=$scale->Translate($start); + if( $this->supress_first ) { + $this->maj_ticks_label[0]=""; + } + else { + if( $this->label_formfunc != '' ) { + $f = $this->label_formfunc; + $this->maj_ticks_label[0]=call_user_func($f,$start); + } + elseif( $this->label_logtype == 0 ) { + $this->maj_ticks_label[0]=$start; + } + else { + $this->maj_ticks_label[0]='10^'.round(log10($start)); + } + } + $i=1; + for($x=$start; $x<=$limit; $x+=$step,++$count ) { + $xs=$scale->Translate($x); + $this->ticks_pos[]=$xs; + $this->ticklabels_pos[]=$xs; + if( $count % 10 == 0 ) { + if( !$this->supress_tickmarks ) { + $img->Line($xs,$pos,$xs,$a2); + } + $this->maj_ticks_pos[$i]=$xs; + $this->maj_ticklabels_pos[$i]=$xs; + + if( $this->label_formfunc != '' ) { + $f = $this->label_formfunc; + $this->maj_ticks_label[$i]=call_user_func($f,$nextMajor); + } + elseif( $this->label_logtype == 0 ) { + $this->maj_ticks_label[$i]=$nextMajor; + } + else { + $this->maj_ticks_label[$i]='10^'.round(log10($nextMajor)); + } + ++$i; + $nextMajor *= 10; + $step *= 10; + $count=1; + } + else { + if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { + $img->Line($xs,$pos,$xs,$a); + } + } + } + } + return true; + } +} // Class +/* EOF */ +?> diff --git a/src/classes/jpgraph/jpgraph_meshinterpolate.inc.php b/src/classes/jpgraph/jpgraph_meshinterpolate.inc.php new file mode 100644 index 0000000..7e8ae53 --- /dev/null +++ b/src/classes/jpgraph/jpgraph_meshinterpolate.inc.php @@ -0,0 +1,105 @@ +Linear($aData,$aFactor); +} + +/** + * Utility class to interpolate a given data matrix + * + */ +class MeshInterpolate { + private $data = array(); + + /** + * Calculate the mid points of the given rectangle which has its top left + * corner at $row,$col. The $aFactordecides how many spliots should be done. + * i.e. how many more divisions should be done recursively + * + * @param $row Top left corner of square to work with + * @param $col Top left corner of square to work with + * $param $aFactor In how many subsquare should we split this square. A value of 1 indicates that no action + */ + function IntSquare( $aRow, $aCol, $aFactor ) { + if ( $aFactor <= 1 ) + return; + + $step = pow( 2, $aFactor-1 ); + + $v0 = $this->data[$aRow][$aCol]; + $v1 = $this->data[$aRow][$aCol + $step]; + $v2 = $this->data[$aRow + $step][$aCol]; + $v3 = $this->data[$aRow + $step][$aCol + $step]; + + $this->data[$aRow][$aCol + $step / 2] = ( $v0 + $v1 ) / 2; + $this->data[$aRow + $step / 2][$aCol] = ( $v0 + $v2 ) / 2; + $this->data[$aRow + $step][$aCol + $step / 2] = ( $v2 + $v3 ) / 2; + $this->data[$aRow + $step / 2][$aCol + $step] = ( $v1 + $v3 ) / 2; + $this->data[$aRow + $step / 2][$aCol + $step / 2] = ( $v0 + $v1 + $v2 + $v3 ) / 4; + + $this->IntSquare( $aRow, $aCol, $aFactor-1 ); + $this->IntSquare( $aRow, $aCol + $step / 2, $aFactor-1 ); + $this->IntSquare( $aRow + $step / 2, $aCol, $aFactor-1 ); + $this->IntSquare( $aRow + $step / 2, $aCol + $step / 2, $aFactor-1 ); + } + + /** + * Interpolate values in a matrice so that the total number of data points + * in vert and horizontal axis are $aIntNbr more. For example $aIntNbr=2 will + * make the data matrice have tiwce as many vertical and horizontal dta points. + * + * Note: This will blow up the matrcide in memory size in the order of $aInNbr^2 + * + * @param $ &$aData The original data matricde + * @param $aInNbr Interpolation factor + * @return the interpolated matrice + */ + function Linear( &$aData, $aIntFactor ) { + $step = pow( 2, $aIntFactor-1 ); + + $orig_cols = count( $aData[0] ); + $orig_rows = count( $aData ); + // Number of new columns/rows + // N = (a-1) * 2^(f-1) + 1 + $p = pow( 2, $aIntFactor-1 ); + $new_cols = $p * ( $orig_cols - 1 ) + 1; + $new_rows = $p * ( $orig_rows - 1 ) + 1; + + $this->data = array_fill( 0, $new_rows, array_fill( 0, $new_cols, 0 ) ); + // Initialize the new matrix with the values that we know + for ( $i = 0; $i < $new_rows; $i++ ) { + for ( $j = 0; $j < $new_cols; $j++ ) { + $v = 0 ; + if ( ( $i % $step == 0 ) && ( $j % $step == 0 ) ) { + $v = $aData[$i / $step][$j / $step]; + } + $this->data[$i][$j] = $v; + } + } + + for ( $i = 0; $i < $new_rows-1; $i += $step ) { + for ( $j = 0; $j < $new_cols-1; $j += $step ) { + $this->IntSquare( $i, $j, $aIntFactor ); + } + } + + return $this->data; + } +} + +?> diff --git a/src/classes/jpgraph/jpgraph_mgraph.php b/src/classes/jpgraph/jpgraph_mgraph.php new file mode 100644 index 0000000..80b2b6d --- /dev/null +++ b/src/classes/jpgraph/jpgraph_mgraph.php @@ -0,0 +1,345 @@ +iWidth = $aWidth; + $this->iHeight = $aHeight; + + // If the cached version exist just read it directly from the + // cache, stream it back to browser and exit + if( $aCachedName!='' && READ_CACHE && $aInline ) { + $this->cache = new ImgStreamCache(); + $this->cache->SetTimeOut($aTimeOut); + $image = new Image(); + if( $this->cache->GetAndStream($image,$aCachedName) ) { + exit(); + } + } + $this->inline = $aInline; + $this->cache_name = $aCachedName; + + $this->title = new Text(); + $this->title->ParagraphAlign('center'); + $this->title->SetFont(FF_FONT2,FS_BOLD); + $this->title->SetMargin(3); + $this->title->SetAlign('center'); + + $this->subtitle = new Text(); + $this->subtitle->ParagraphAlign('center'); + $this->subtitle->SetFont(FF_FONT1,FS_BOLD); + $this->subtitle->SetMargin(3); + $this->subtitle->SetAlign('center'); + + $this->subsubtitle = new Text(); + $this->subsubtitle->ParagraphAlign('center'); + $this->subsubtitle->SetFont(FF_FONT1,FS_NORMAL); + $this->subsubtitle->SetMargin(3); + $this->subsubtitle->SetAlign('center'); + + $this->footer = new Footer(); + + } + + // Specify background fill color for the combined graph + function SetFillColor($aColor) { + $this->iFillColor = $aColor; + } + + // Add a frame around the combined graph + function SetFrame($aFlg,$aColor='black',$aWeight=1) { + $this->iDoFrame = $aFlg; + $this->iFrameColor = $aColor; + $this->iFrameWeight = $aWeight; + } + + // Specify a background image blend + function SetBackgroundImageMix($aMix) { + $this->background_image_mix = $aMix ; + } + + // Specify a background image + function SetBackgroundImage($aFileName,$aCenter_aX=NULL,$aY=NULL) { + // Second argument can be either a boolean value or + // a numeric + $aCenter=TRUE; + $aX=NULL; + + if( is_numeric($aCenter_aX) ) { + $aX=$aCenter_aX; + } + + // Get extension to determine image type + $e = explode('.',$aFileName); + if( !$e ) { + JpGraphError::RaiseL(12002,$aFileName); + //('Incorrect file name for MGraph::SetBackgroundImage() : '.$aFileName.' Must have a valid image extension (jpg,gif,png) when using autodetection of image type'); + } + + $valid_formats = array('png', 'jpg', 'gif'); + $aImgFormat = strtolower($e[count($e)-1]); + if ($aImgFormat == 'jpeg') { + $aImgFormat = 'jpg'; + } + elseif (!in_array($aImgFormat, $valid_formats) ) { + JpGraphError::RaiseL(12003,$aImgFormat,$aFileName); + //('Unknown file extension ($aImgFormat) in MGraph::SetBackgroundImage() for filename: '.$aFileName); + } + + $this->background_image = $aFileName; + $this->background_image_center=$aCenter; + $this->background_image_format=$aImgFormat; + $this->background_image_x = $aX; + $this->background_image_y = $aY; + } + + function _strokeBackgroundImage() { + if( $this->background_image == '' ) return; + + $bkgimg = Graph::LoadBkgImage('',$this->background_image); + + // Background width & Heoght + $bw = imagesx($bkgimg); + $bh = imagesy($bkgimg); + + // Canvas width and height + $cw = imagesx($this->img); + $ch = imagesy($this->img); + + if( $this->doshadow ) { + $cw -= $this->shadow_width; + $ch -= $this->shadow_width; + } + + if( $this->background_image_x === NULL || $this->background_image_y === NULL ) { + if( $this->background_image_center ) { + // Center original image in the plot area + $x = round($cw/2-$bw/2); $y = round($ch/2-$bh/2); + } + else { + // Just copy the image from left corner, no resizing + $x=0; $y=0; + } + } + else { + $x = $this->background_image_x; + $y = $this->background_image_y; + } + imagecopymerge($this->img,$bkgimg,$x,$y,0,0,$bw,$bh,$this->background_image_mix); + } + + function AddMix($aGraph,$x=0,$y=0,$mix=100,$fx=0,$fy=0,$w=0,$h=0) { + $this->_gdImgHandle($aGraph->Stroke( _IMG_HANDLER),$x,$y,$fx=0,$fy=0,$w,$h,$mix); + } + + function Add($aGraph,$x=0,$y=0,$fx=0,$fy=0,$w=0,$h=0) { + $this->_gdImgHandle($aGraph->Stroke( _IMG_HANDLER),$x,$y,$fx=0,$fy=0,$w,$h); + } + + function _gdImgHandle($agdCanvas,$x,$y,$fx=0,$fy=0,$w=0,$h=0,$mix=100) { + if( $w == 0 ) { + $w = @imagesx($agdCanvas); + } + if( $w === NULL ) { + JpGraphError::RaiseL(12007); + //('Argument to MGraph::Add() is not a valid GD image handle.'); + return; + } + if( $h == 0 ) { + $h = @imagesy($agdCanvas); + } + $this->iGraphs[$this->iCnt++] = array($agdCanvas,$x,$y,$fx,$fy,$w,$h,$mix); + } + + function SetMargin($lm,$rm,$tm,$bm) { + $this->lm = $lm; + $this->rm = $rm; + $this->tm = $tm; + $this->bm = $bm; + } + + function SetExpired($aFlg=true) { + $this->expired = $aFlg; + } + + function SetImgFormat($aFormat,$aQuality=75) { + $this->image_format = $aFormat; + $this->image_quality = $aQuality; + } + + // Set the shadow around the whole image + function SetShadow($aShowShadow=true,$aShadowWidth=4,$aShadowColor='gray@0.3') { + $this->doshadow = $aShowShadow; + $this->shadow_color = $aShadowColor; + $this->shadow_width = $aShadowWidth; + $this->footer->iBottomMargin += $aShadowWidth; + $this->footer->iRightMargin += $aShadowWidth; + } + + function StrokeTitle($image,$w,$h) { + // Stroke title + if( $this->title->t !== '' ) { + + $margin = 3; + + $y = $this->title->margin; + if( $this->title->halign == 'center' ) { + $this->title->Center(0,$w,$y); + } + elseif( $this->title->halign == 'left' ) { + $this->title->SetPos($this->title->margin+2,$y); + } + elseif( $this->title->halign == 'right' ) { + $indent = 0; + if( $this->doshadow ) { + $indent = $this->shadow_width+2; + } + $this->title->SetPos($w-$this->title->margin-$indent,$y,'right'); + } + $this->title->Stroke($image); + + // ... and subtitle + $y += $this->title->GetTextHeight($image) + $margin + $this->subtitle->margin; + if( $this->subtitle->halign == 'center' ) { + $this->subtitle->Center(0,$w,$y); + } + elseif( $this->subtitle->halign == 'left' ) { + $this->subtitle->SetPos($this->subtitle->margin+2,$y); + } + elseif( $this->subtitle->halign == 'right' ) { + $indent = 0; + if( $this->doshadow ) { + $indent = $this->shadow_width+2; + } + $this->subtitle->SetPos($this->img->width-$this->subtitle->margin-$indent,$y,'right'); + } + $this->subtitle->Stroke($image); + + // ... and subsubtitle + $y += $this->subtitle->GetTextHeight($image) + $margin + $this->subsubtitle->margin; + if( $this->subsubtitle->halign == 'center' ) { + $this->subsubtitle->Center(0,$w,$y); + } + elseif( $this->subsubtitle->halign == 'left' ) { + $this->subsubtitle->SetPos($this->subsubtitle->margin+2,$y); + } + elseif( $this->subsubtitle->halign == 'right' ) { + $indent = 0; + if( $this->doshadow ) { + $indent = $this->shadow_width+2; + } + $this->subsubtitle->SetPos($w-$this->subsubtitle->margin-$indent,$y,'right'); + } + $this->subsubtitle->Stroke($image); + + } + } + + function Stroke($aFileName='') { + // Find out the necessary size for the container image + $w=0; $h=0; + for($i=0; $i < $this->iCnt; ++$i ) { + $maxw = $this->iGraphs[$i][1]+$this->iGraphs[$i][5]; + $maxh = $this->iGraphs[$i][2]+$this->iGraphs[$i][6]; + $w = max( $w, $maxw ); + $h = max( $h, $maxh ); + } + $w += $this->lm+$this->rm; + $h += $this->tm+$this->bm; + + // User specified width,height overrides + if( $this->iWidth !== NULL && $this->iWidth !== 0 ) $w = $this->iWidth; + if( $this->iHeight!== NULL && $this->iHeight !== 0) $h = $this->iHeight; + + if( $this->doshadow ) { + $w += $this->shadow_width; + $h += $this->shadow_width; + } + + $image = new Image($w,$h); + $image->SetImgFormat( $this->image_format,$this->image_quality); + + if( $this->doshadow ) { + $image->SetColor($this->iFrameColor); + $image->ShadowRectangle(0,0,$w-1,$h-1,$this->iFillColor,$this->shadow_width,$this->shadow_color); + $w -= $this->shadow_width; + $h -= $this->shadow_width; + } + else { + $image->SetColor($this->iFillColor); + $image->FilledRectangle(0,0,$w-1,$h-1); + } + $image->SetExpired($this->expired); + + $this->img = $image->img; + $this->_strokeBackgroundImage(); + + if( $this->iDoFrame && ! $this->doshadow ) { + $image->SetColor($this->iFrameColor); + $image->SetLineWeight($this->iFrameWeight); + $image->Rectangle(0,0,$w-1,$h-1); + } + + // Copy all sub graphs to the container + for($i=0; $i < $this->iCnt; ++$i ) { + $image->CopyMerge($this->iGraphs[$i][0], + $this->iGraphs[$i][1]+$this->lm,$this->iGraphs[$i][2]+$this->tm, + $this->iGraphs[$i][3],$this->iGraphs[$i][4], + $this->iGraphs[$i][5],$this->iGraphs[$i][6], + -1,-1, /* Full from width and height */ + $this->iGraphs[$i][7]); + + + } + + $this->StrokeTitle($image,$w,$h); + $this->footer->Stroke($image); + + // Output image + if( $aFileName == _IMG_HANDLER ) { + return $image->img; + } + else { + //Finally stream the generated picture + $this->cache = new ImgStreamCache(); + $this->cache->PutAndStream($image,$this->cache_name,$this->inline,$aFileName); + } + } +} + +// EOF + +?> diff --git a/src/classes/jpgraph/jpgraph_pie.php b/src/classes/jpgraph/jpgraph_pie.php index a4208b4..c79d30f 100644 --- a/src/classes/jpgraph/jpgraph_pie.php +++ b/src/classes/jpgraph/jpgraph_pie.php @@ -5,7 +5,7 @@ // Created: 2001-02-14 // Ver: $Id: jpgraph_pie.php 1926 2010-01-11 16:33:07Z ljp $ // - // Copyright (c) Aditus Consulting. All rights reserved. + // Copyright (c) Asial Corporation. All rights reserved. //======================================================================== */ @@ -23,6 +23,9 @@ define("PIE_VALUE_ADJPER",2); //=================================================== class PiePlot { public $posx=0.5,$posy=0.5; + public $is_using_plot_theme = false; + public $theme="earth"; + protected $use_plot_theme_colors = false; protected $radius=0.3; protected $explode_radius=array(),$explode_all=false,$explode_r=20; protected $labels=null, $legends=null; @@ -39,7 +42,6 @@ class PiePlot { "pastel" => array(27,415,128,59,66,79,105,110,42,147,152,230,236,240,331,337,405,38), "water" => array(8,370,24,40,335,56,213,237,268,14,326,387,10,388), "sand" => array(27,168,34,170,19,50,65,72,131,209,46,393)); - protected $theme="earth"; protected $setslicecolors=array(); protected $labeltype=0; // Default to percentage protected $pie_border=true,$pie_interior_border=true; @@ -59,7 +61,7 @@ class PiePlot { function __construct($data) { $this->data = array_reverse($data); $this->title = new Text(""); - $this->title->SetFont(FF_FONT1,FS_BOLD); + $this->title->SetFont(FF_DEFAULT,FS_BOLD); $this->value = new DisplayValue(); $this->value->Show(); $this->value->SetFormat('%.1f%%'); @@ -177,10 +179,15 @@ class PiePlot { function SetTheme($aTheme) { - if( in_array($aTheme,array_keys($this->themearr)) ) - $this->theme = $aTheme; - else - JpGraphError::RaiseL(15001,$aTheme);//("PiePLot::SetTheme() Unknown theme: $aTheme"); +// JpGraphError::RaiseL(15012,$aTheme); +// return; + + if( in_array($aTheme,array_keys($this->themearr)) ) { + $this->theme = $aTheme; + $this->is_using_plot_theme = true; + } else { + JpGraphError::RaiseL(15001,$aTheme);//("PiePLot::SetTheme() Unknown theme: $aTheme"); + } } function ExplodeSlice($e,$radius=20) { @@ -398,6 +405,10 @@ class PiePlot { $this->adjusted_data = $this->AdjPercentage($this->data); } + if ($this->use_plot_theme_colors) { + $this->setslicecolors = null; + } + $colors = array_keys($img->rgb->rgb_table); sort($colors); $ta=$this->themearr[$this->theme]; @@ -1018,6 +1029,10 @@ class PiePlot { $this->value->Stroke($img,$label,$xt-$dx*$w,$yt-$dy*$h); } } + + function UsePlotThemeColors($flag = true) { + $this->use_plot_theme_colors = $flag; + } } // Class @@ -1233,6 +1248,10 @@ class PieGraph extends Graph { $this->posx=$width/2; $this->posy=$height/2; $this->SetColor(array(255,255,255)); + + if ($this->graph_theme) { + $this->graph_theme->ApplyGraph($this); + } } //--------------- @@ -1252,13 +1271,26 @@ class PieGraph extends Graph { if( is_array($aObj) ) { $n = count($aObj); for($i=0; $i < $n; ++$i ) { + //if ($aObj[$i]->theme) { + // $this->ClearTheme(); + //} $this->plots[] = $aObj[$i]; } } else { + //if ($aObj->theme) { + // $this->ClearTheme(); + //} $this->plots[] = $aObj; } } + + if ($this->graph_theme) { + $this->graph_theme->SetupPlot($aObj); + if ($aObj->is_using_plot_theme) { + $aObj->UsePlotThemeColors(); + } + } } function SetAntiAliasing($aFlg=true) { @@ -1303,6 +1335,7 @@ class PieGraph extends Graph { // Method description function Stroke($aStrokeFileName="") { + // If the filename is the predefined value = '_csim_special_' // we assume that the call to stroke only needs to do enough // to correctly generate the CSIM maps. diff --git a/src/classes/jpgraph/jpgraph_pie3d.php b/src/classes/jpgraph/jpgraph_pie3d.php index 45cb2b2..52b8631 100644 --- a/src/classes/jpgraph/jpgraph_pie3d.php +++ b/src/classes/jpgraph/jpgraph_pie3d.php @@ -5,7 +5,7 @@ // Created: 2001-03-24 // Ver: $Id: jpgraph_pie3d.php 1329 2009-06-20 19:23:30Z ljp $ // - // Copyright (c) Aditus Consulting. All rights reserved. + // Copyright (c) Asial Corporation. All rights reserved. //======================================================================== */ diff --git a/src/classes/jpgraph/jpgraph_plotband.php b/src/classes/jpgraph/jpgraph_plotband.php index 1c78d33..b7aef75 100644 --- a/src/classes/jpgraph/jpgraph_plotband.php +++ b/src/classes/jpgraph/jpgraph_plotband.php @@ -5,7 +5,7 @@ // Created: 2004-02-18 // Ver: $Id: jpgraph_plotband.php 1106 2009-02-22 20:16:35Z ljp $ // -// Copyright (c) Aditus Consulting. All rights reserved. +// Copyright (c) Asial Corporation. All rights reserved. //======================================================================== // Constants for types of static bands in plot area diff --git a/src/classes/jpgraph/jpgraph_plotline.php b/src/classes/jpgraph/jpgraph_plotline.php new file mode 100644 index 0000000..4ee0f56 --- /dev/null +++ b/src/classes/jpgraph/jpgraph_plotline.php @@ -0,0 +1,142 @@ +direction = $aDir; + $this->color=$aColor; + $this->weight=$aWeight; + $this->scaleposition=$aPos; + } + + function SetLegend($aLegend,$aCSIM='',$aCSIMAlt='',$aCSIMWinTarget='') { + $this->legend = $aLegend; + $this->legendcsimtarget = $aCSIM; + $this->legendcsimwintarget = $aCSIMWinTarget; + $this->legendcsimalt = $aCSIMAlt; + } + + function HideLegend($f=true) { + $this->hidelegend = $f; + } + + function SetPosition($aScalePosition) { + $this->scaleposition=$aScalePosition; + } + + function SetDirection($aDir) { + $this->direction = $aDir; + } + + function SetColor($aColor) { + $this->color=$aColor; + } + + function SetWeight($aWeight) { + $this->weight=$aWeight; + } + + function SetLineStyle($aStyle) { + $this->iLineStyle = $aStyle; + } + + function GetCSIMAreas() { + return ''; + } + + //--------------- + // PRIVATE METHODS + + function DoLegend($graph) { + if( !$this->hidelegend ) $this->Legend($graph); + } + + // Framework function the chance for each plot class to set a legend + function Legend($aGraph) { + if( $this->legend != '' ) { + $dummyPlotMark = new PlotMark(); + $lineStyle = 1; + $aGraph->legend->Add($this->legend,$this->color,$dummyPlotMark,$lineStyle, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + } + + function PreStrokeAdjust($aGraph) { + // Nothing to do + } + + // Called by framework to allow the object to draw + // optional information in the margin area + function StrokeMargin($aImg) { + // Nothing to do + } + + // Framework function to allow the object to adjust the scale + function PrescaleSetup($aGraph) { + // Nothing to do + } + + function Min() { + return array(null,null); + } + + function Max() { + return array(null,null); + } + + function _Stroke($aImg,$aMinX,$aMinY,$aMaxX,$aMaxY,$aXPos,$aYPos) { + $aImg->SetColor($this->color); + $aImg->SetLineWeight($this->weight); + $oldStyle = $aImg->SetLineStyle($this->iLineStyle); + if( $this->direction == VERTICAL ) { + $ymin_abs = $aMinY; + $ymax_abs = $aMaxY; + $xpos_abs = $aXPos; + $aImg->StyleLine($xpos_abs, $ymin_abs, $xpos_abs, $ymax_abs); + } + elseif( $this->direction == HORIZONTAL ) { + $xmin_abs = $aMinX; + $xmax_abs = $aMaxX; + $ypos_abs = $aYPos; + $aImg->StyleLine($xmin_abs, $ypos_abs, $xmax_abs, $ypos_abs); + } + else { + JpGraphError::RaiseL(25125);//(" Illegal direction for static line"); + } + $aImg->SetLineStyle($oldStyle); + } + + function Stroke($aImg,$aXScale,$aYScale) { + $this->_Stroke($aImg, + $aImg->left_margin, + $aYScale->Translate($aYScale->GetMinVal()), + $aImg->width-$aImg->right_margin, + $aYScale->Translate($aYScale->GetMaxVal()), + $aXScale->Translate($this->scaleposition), + $aYScale->Translate($this->scaleposition) + ); + } +} + + +?> diff --git a/src/classes/jpgraph/jpgraph_plotmark.inc.php b/src/classes/jpgraph/jpgraph_plotmark.inc.php index 78a08cf..29c4d03 100644 --- a/src/classes/jpgraph/jpgraph_plotmark.inc.php +++ b/src/classes/jpgraph/jpgraph_plotmark.inc.php @@ -5,7 +5,7 @@ // Created: 2003-03-21 // Ver: $Id: jpgraph_plotmark.inc.php 1106 2009-02-22 20:16:35Z ljp $ // -// Copyright (c) Aditus Consulting. All rights reserved. +// Copyright (c) Asial Corporation. All rights reserved. //======================================================================== @@ -501,4 +501,4 @@ class FlagCache { } } -?> \ No newline at end of file +?> diff --git a/src/classes/jpgraph/jpgraph_polar.php b/src/classes/jpgraph/jpgraph_polar.php new file mode 100644 index 0000000..62c6bbc --- /dev/null +++ b/src/classes/jpgraph/jpgraph_polar.php @@ -0,0 +1,897 @@ +numpoints = $n/2; + $this->coord = $aData; + $this->mark = new PlotMark(); + } + + function SetWeight($aWeight) { + $this->iLineWeight = $aWeight; + } + + function SetColor($aColor){ + $this->iColor = $aColor; + } + + function SetFillColor($aColor){ + $this->iFillColor = $aColor; + } + + function Max() { + $m = $this->coord[1]; + $i=1; + while( $i < $this->numpoints ) { + $m = max($m,$this->coord[2*$i+1]); + ++$i; + } + return $m; + } + // Set href targets for CSIM + function SetCSIMTargets($aTargets,$aAlts=null) { + $this->csimtargets=$aTargets; + $this->csimalts=$aAlts; + } + + // Get all created areas + function GetCSIMareas() { + return $this->csimareas; + } + + function SetLegend($aLegend,$aCSIM="",$aCSIMAlt="") { + $this->legend = $aLegend; + $this->legendcsimtarget = $aCSIM; + $this->legendcsimalt = $aCSIMAlt; + } + + // Private methods + + function Legend($aGraph) { + $color = $this->iColor ; + if( $this->legend != "" ) { + if( $this->iFillColor!='' ) { + $color = $this->iFillColor; + $aGraph->legend->Add($this->legend,$color,$this->mark,0, + $this->legendcsimtarget,$this->legendcsimalt); + } + else { + $aGraph->legend->Add($this->legend,$color,$this->mark,$this->line_style, + $this->legendcsimtarget,$this->legendcsimalt); + } + } + } + + function Stroke($img,$scale) { + + $i=0; + $p=array(); + $this->csimareas=''; + while($i < $this->numpoints) { + list($x1,$y1) = $scale->PTranslate($this->coord[2*$i],$this->coord[2*$i+1]); + $p[2*$i] = $x1; + $p[2*$i+1] = $y1; + + if( isset($this->csimtargets[$i]) ) { + $this->mark->SetCSIMTarget($this->csimtargets[$i]); + $this->mark->SetCSIMAlt($this->csimalts[$i]); + $this->mark->SetCSIMAltVal($this->coord[2*$i], $this->coord[2*$i+1]); + $this->mark->Stroke($img,$x1,$y1); + $this->csimareas .= $this->mark->GetCSIMAreas(); + } + else { + $this->mark->Stroke($img,$x1,$y1); + } + + ++$i; + } + + if( $this->iFillColor != '' ) { + $img->SetColor($this->iFillColor); + $img->FilledPolygon($p); + } + $img->SetLineWeight($this->iLineWeight); + $img->SetColor($this->iColor); + $img->Polygon($p,$this->iFillColor!=''); + } +} + +//-------------------------------------------------------------------------- +// class PolarAxis +//-------------------------------------------------------------------------- +class PolarAxis extends Axis { + private $angle_step=15,$angle_color='lightgray',$angle_label_color='black'; + private $angle_fontfam=FF_FONT1,$angle_fontstyle=FS_NORMAL,$angle_fontsize=10; + private $angle_fontcolor = 'navy'; + private $gridminor_color='lightgray',$gridmajor_color='lightgray'; + private $show_minor_grid = false, $show_major_grid = true ; + private $show_angle_mark=true, $show_angle_grid=true, $show_angle_label=true; + private $angle_tick_len=3, $angle_tick_len2=3, $angle_tick_color='black'; + private $show_angle_tick=true; + private $radius_tick_color='black'; + + function __construct($img,$aScale) { + parent::__construct($img,$aScale); + } + + function ShowAngleDegreeMark($aFlg=true) { + $this->show_angle_mark = $aFlg; + } + + function SetAngleStep($aStep) { + $this->angle_step=$aStep; + } + + function HideTicks($aFlg=true,$aAngleFlg=true) { + parent::HideTicks($aFlg,$aFlg); + $this->show_angle_tick = !$aAngleFlg; + } + + function ShowAngleLabel($aFlg=true) { + $this->show_angle_label = $aFlg; + } + + function ShowGrid($aMajor=true,$aMinor=false,$aAngle=true) { + $this->show_minor_grid = $aMinor; + $this->show_major_grid = $aMajor; + $this->show_angle_grid = $aAngle ; + } + + function SetAngleFont($aFontFam,$aFontStyle=FS_NORMAL,$aFontSize=10) { + $this->angle_fontfam = $aFontFam; + $this->angle_fontstyle = $aFontStyle; + $this->angle_fontsize = $aFontSize; + } + + function SetColor($aColor,$aRadColor='',$aAngleColor='') { + if( $aAngleColor == '' ) + $aAngleColor=$aColor; + parent::SetColor($aColor,$aRadColor); + $this->angle_fontcolor = $aAngleColor; + } + + function SetGridColor($aMajorColor,$aMinorColor='',$aAngleColor='') { + if( $aMinorColor == '' ) + $aMinorColor = $aMajorColor; + if( $aAngleColor == '' ) + $aAngleColor = $aMajorColor; + + $this->gridminor_color = $aMinorColor; + $this->gridmajor_color = $aMajorColor; + $this->angle_color = $aAngleColor; + } + + function SetTickColors($aRadColor,$aAngleColor='') { + $this->radius_tick_color = $aRadColor; + $this->angle_tick_color = $aAngleColor; + } + + // Private methods + function StrokeGrid($pos) { + $x = round($this->img->left_margin + $this->img->plotwidth/2); + $this->scale->ticks->Stroke($this->img,$this->scale,$pos); + + // Stroke the minor arcs + $pmin = array(); + $p = $this->scale->ticks->ticks_pos; + $n = count($p); + $i = 0; + $this->img->SetColor($this->gridminor_color); + while( $i < $n ) { + $r = $p[$i]-$x+1; + $pmin[]=$r; + if( $this->show_minor_grid ) { + $this->img->Circle($x,$pos,$r); + } + $i++; + } + + $limit = max($this->img->plotwidth,$this->img->plotheight)*1.4 ; + while( $r < $limit ) { + $off = $r; + $i=1; + $r = $off + round($p[$i]-$x+1); + while( $r < $limit && $i < $n ) { + $r = $off+$p[$i]-$x; + $pmin[]=$r; + if( $this->show_minor_grid ) { + $this->img->Circle($x,$pos,$r); + } + $i++; + } + } + + // Stroke the major arcs + if( $this->show_major_grid ) { + // First determine how many minor step on + // every major step. We have recorded the minor radius + // in pmin and use these values. This is done in order + // to avoid rounding errors if we were to recalculate the + // different major radius. + $pmaj = $this->scale->ticks->maj_ticks_pos; + $p = $this->scale->ticks->ticks_pos; + if( $this->scale->name == 'lin' ) { + $step=round(($pmaj[1] - $pmaj[0])/($p[1] - $p[0])); + } + else { + $step=9; + } + $n = round(count($pmin)/$step); + $i = 0; + $this->img->SetColor($this->gridmajor_color); + $limit = max($this->img->plotwidth,$this->img->plotheight)*1.4 ; + $off = $r; + $i=0; + $r = $pmin[$i*$step]; + while( $r < $limit && $i < $n ) { + $r = $pmin[$i*$step]; + $this->img->Circle($x,$pos,$r); + $i++; + } + } + + // Draw angles + if( $this->show_angle_grid ) { + $this->img->SetColor($this->angle_color); + $d = max($this->img->plotheight,$this->img->plotwidth)*1.4 ; + $a = 0; + $p = $this->scale->ticks->ticks_pos; + $start_radius = $p[1]-$x; + while( $a < 360 ) { + if( $a == 90 || $a == 270 ) { + // Make sure there are no rounding problem with + // exactly vertical lines + $this->img->Line($x+$start_radius*cos($a/180*M_PI)+1, + $pos-$start_radius*sin($a/180*M_PI), + $x+$start_radius*cos($a/180*M_PI)+1, + $pos-$d*sin($a/180*M_PI)); + + } + else { + $this->img->Line($x+$start_radius*cos($a/180*M_PI)+1, + $pos-$start_radius*sin($a/180*M_PI), + $x+$d*cos($a/180*M_PI), + $pos-$d*sin($a/180*M_PI)); + } + $a += $this->angle_step; + } + } + } + + function StrokeAngleLabels($pos,$type) { + + if( !$this->show_angle_label ) + return; + + $x0 = round($this->img->left_margin+$this->img->plotwidth/2)+1; + + $d = max($this->img->plotwidth,$this->img->plotheight)*1.42; + $a = $this->angle_step; + $t = new Text(); + $t->SetColor($this->angle_fontcolor); + $t->SetFont($this->angle_fontfam,$this->angle_fontstyle,$this->angle_fontsize); + $xright = $this->img->width - $this->img->right_margin; + $ytop = $this->img->top_margin; + $xleft = $this->img->left_margin; + $ybottom = $this->img->height - $this->img->bottom_margin; + $ha = 'left'; + $va = 'center'; + $w = $this->img->plotwidth/2; + $h = $this->img->plotheight/2; + $xt = $x0; $yt = $pos; + $margin=5; + + $tl = $this->angle_tick_len ; // Outer len + $tl2 = $this->angle_tick_len2 ; // Interior len + + $this->img->SetColor($this->angle_tick_color); + $rot90 = $this->img->a == 90 ; + + if( $type == POLAR_360 ) { + + // Corner angles of the four corners + $ca1 = atan($h/$w)/M_PI*180; + $ca2 = 180-$ca1; + $ca3 = $ca1+180; + $ca4 = 360-$ca1; + $end = 360; + + while( $a < $end ) { + $ca = cos($a/180*M_PI); + $sa = sin($a/180*M_PI); + $x = $d*$ca; + $y = $d*$sa; + $xt=1000;$yt=1000; + if( $a <= $ca1 || $a >= $ca4 ) { + $yt = $pos - $w * $y/$x; + $xt = $xright + $margin; + if( $rot90 ) { + $ha = 'center'; + $va = 'top'; + } + else { + $ha = 'left'; + $va = 'center'; + } + $x1=$xright-$tl2; $x2=$xright+$tl; + $y1=$y2=$yt; + } + elseif( $a > $ca1 && $a < $ca2 ) { + $xt = $x0 + $h * $x/$y; + $yt = $ytop - $margin; + if( $rot90 ) { + $ha = 'left'; + $va = 'center'; + } + else { + $ha = 'center'; + $va = 'bottom'; + } + $y1=$ytop+$tl2;$y2=$ytop-$tl; + $x1=$x2=$xt; + } + elseif( $a >= $ca2 && $a <= $ca3 ) { + $yt = $pos + $w * $y/$x; + $xt = $xleft - $margin; + if( $rot90 ) { + $ha = 'center'; + $va = 'bottom'; + } + else { + $ha = 'right'; + $va = 'center'; + } + $x1=$xleft+$tl2;$x2=$xleft-$tl; + $y1=$y2=$yt; + } + else { + $xt = $x0 - $h * $x/$y; + $yt = $ybottom + $margin; + if( $rot90 ) { + $ha = 'right'; + $va = 'center'; + } + else { + $ha = 'center'; + $va = 'top'; + } + $y1=$ybottom-$tl2;$y2=$ybottom+$tl; + $x1=$x2=$xt; + } + if( $a != 0 && $a != 180 ) { + $t->Align($ha,$va); + if( $this->scale->clockwise ) { + $t->Set(360-$a); + } + else { + $t->Set($a); + } + if( $this->show_angle_mark && $t->font_family > 4 ) { + $a .= SymChar::Get('degree'); + } + $t->Stroke($this->img,$xt,$yt); + if( $this->show_angle_tick ) { + $this->img->Line($x1,$y1,$x2,$y2); + } + } + $a += $this->angle_step; + } + } + else { + // POLAR_HALF + $ca1 = atan($h/$w*2)/M_PI*180; + $ca2 = 180-$ca1; + $end = 180; + while( $a < $end ) { + $ca = cos($a/180*M_PI); + $sa = sin($a/180*M_PI); + $x = $d*$ca; + $y = $d*$sa; + if( $a <= $ca1 ) { + $yt = $pos - $w * $y/$x; + $xt = $xright + $margin; + if( $rot90 ) { + $ha = 'center'; + $va = 'top'; + } + else { + $ha = 'left'; + $va = 'center'; + } + $x1=$xright-$tl2; $x2=$xright+$tl; + $y1=$y2=$yt; + } + elseif( $a > $ca1 && $a < $ca2 ) { + $xt = $x0 + 2*$h * $x/$y; + $yt = $ytop - $margin; + if( $rot90 ) { + $ha = 'left'; + $va = 'center'; + } + else { + $ha = 'center'; + $va = 'bottom'; + } + $y1=$ytop+$tl2;$y2=$ytop-$tl; + $x1=$x2=$xt; + } + elseif( $a >= $ca2 ) { + $yt = $pos + $w * $y/$x; + $xt = $xleft - $margin; + if( $rot90 ) { + $ha = 'center'; + $va = 'bottom'; + } + else { + $ha = 'right'; + $va = 'center'; + } + $x1=$xleft+$tl2;$x2=$xleft-$tl; + $y1=$y2=$yt; + } + $t->Align($ha,$va); + if( $this->show_angle_mark && $t->font_family > 4 ) { + $a .= SymChar::Get('degree'); + } + $t->Set($a); + $t->Stroke($this->img,$xt,$yt); + if( $this->show_angle_tick ) { + $this->img->Line($x1,$y1,$x2,$y2); + } + $a += $this->angle_step; + } + } + } + + function Stroke($pos,$dummy=true) { + + $this->img->SetLineWeight($this->weight); + $this->img->SetColor($this->color); + $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); + if( !$this->hide_line ) { + $this->img->FilledRectangle($this->img->left_margin,$pos, + $this->img->width-$this->img->right_margin, + $pos+$this->weight-1); + } + $y=$pos+$this->img->GetFontHeight()+$this->title_margin+$this->title->margin; + if( $this->title_adjust=="high" ) { + $this->title->SetPos($this->img->width-$this->img->right_margin,$y,"right","top"); + } + elseif( $this->title_adjust=="middle" || $this->title_adjust=="center" ) { + $this->title->SetPos(($this->img->width-$this->img->left_margin-$this->img->right_margin)/2+$this->img->left_margin, + $y,"center","top"); + } + elseif($this->title_adjust=="low") { + $this->title->SetPos($this->img->left_margin,$y,"left","top"); + } + else { + JpGraphError::RaiseL(17002,$this->title_adjust); + //('Unknown alignment specified for X-axis title. ('.$this->title_adjust.')'); + } + + + if (!$this->hide_labels) { + $this->StrokeLabels($pos,false); + } + $this->img->SetColor($this->radius_tick_color); + $this->scale->ticks->Stroke($this->img,$this->scale,$pos); + + // + // Mirror the positions for the left side of the scale + // + $mid = 2*($this->img->left_margin+$this->img->plotwidth/2); + $n = count($this->scale->ticks->ticks_pos); + $i=0; + while( $i < $n ) { + $this->scale->ticks->ticks_pos[$i] = + $mid-$this->scale->ticks->ticks_pos[$i] ; + ++$i; + } + + $n = count($this->scale->ticks->maj_ticks_pos); + $i=0; + while( $i < $n ) { + $this->scale->ticks->maj_ticks_pos[$i] = + $mid-$this->scale->ticks->maj_ticks_pos[$i] ; + ++$i; + } + + $n = count($this->scale->ticks->maj_ticklabels_pos); + $i=1; + while( $i < $n ) { + $this->scale->ticks->maj_ticklabels_pos[$i] = + $mid-$this->scale->ticks->maj_ticklabels_pos[$i] ; + ++$i; + } + + // Draw the left side of the scale + $n = count($this->scale->ticks->ticks_pos); + $yu = $pos - $this->scale->ticks->direction*$this->scale->ticks->GetMinTickAbsSize(); + + + // Minor ticks + if( ! $this->scale->ticks->supress_minor_tickmarks ) { + $i=1; + while( $i < $n/2 ) { + $x = round($this->scale->ticks->ticks_pos[$i]) ; + $this->img->Line($x,$pos,$x,$yu); + ++$i; + } + } + + $n = count($this->scale->ticks->maj_ticks_pos); + $yu = $pos - $this->scale->ticks->direction*$this->scale->ticks->GetMajTickAbsSize(); + + + // Major ticks + if( ! $this->scale->ticks->supress_tickmarks ) { + $i=1; + while( $i < $n/2 ) { + $x = round($this->scale->ticks->maj_ticks_pos[$i]) ; + $this->img->Line($x,$pos,$x,$yu); + ++$i; + } + } + if (!$this->hide_labels) { + $this->StrokeLabels($pos,false); + } + $this->title->Stroke($this->img); + } +} + +class PolarScale extends LinearScale { + private $graph; + public $clockwise=false; + + function __construct($aMax,$graph,$aClockwise) { + parent::__construct(0,$aMax,'x'); + $this->graph = $graph; + $this->clockwise = $aClockwise; + } + + function SetClockwise($aFlg) { + $this->clockwise = $aFlg; + } + + function _Translate($v) { + return parent::Translate($v); + } + + function PTranslate($aAngle,$aRad) { + + $m = $this->scale[1]; + $w = $this->graph->img->plotwidth/2; + $aRad = $aRad/$m*$w; + + $a = $aAngle/180 * M_PI; + if( $this->clockwise ) { + $a = 2*M_PI-$a; + } + + $x = cos($a) * $aRad; + $y = sin($a) * $aRad; + + $x += $this->_Translate(0); + + if( $this->graph->iType == POLAR_360 ) { + $y = ($this->graph->img->top_margin + $this->graph->img->plotheight/2) - $y; + } + else { + $y = ($this->graph->img->top_margin + $this->graph->img->plotheight) - $y; + } + return array($x,$y); + } +} + +class PolarLogScale extends LogScale { + private $graph; + public $clockwise=false; + + function __construct($aMax,$graph,$aClockwise=false) { + parent::__construct(0,$aMax,'x'); + $this->graph = $graph; + $this->ticks->SetLabelLogType(LOGLABELS_MAGNITUDE); + $this->clockwise = $aClockwise; + + } + + function SetClockwise($aFlg) { + $this->clockwise = $aFlg; + } + + function PTranslate($aAngle,$aRad) { + + if( $aRad == 0 ) + $aRad = 1; + $aRad = log10($aRad); + $m = $this->scale[1]; + $w = $this->graph->img->plotwidth/2; + $aRad = $aRad/$m*$w; + + $a = $aAngle/180 * M_PI; + if( $this->clockwise ) { + $a = 2*M_PI-$a; + } + + $x = cos( $a ) * $aRad; + $y = sin( $a ) * $aRad; + + $x += $w+$this->graph->img->left_margin;//$this->_Translate(0); + if( $this->graph->iType == POLAR_360 ) { + $y = ($this->graph->img->top_margin + $this->graph->img->plotheight/2) - $y; + } + else { + $y = ($this->graph->img->top_margin + $this->graph->img->plotheight) - $y; + } + return array($x,$y); + } +} + +class PolarGraph extends Graph { + public $scale; + public $axis; + public $iType=POLAR_360; + private $iClockwise=false; + + function __construct($aWidth=300,$aHeight=200,$aCachedName="",$aTimeOut=0,$aInline=true) { + parent::__construct($aWidth,$aHeight,$aCachedName,$aTimeOut,$aInline) ; + $this->SetDensity(TICKD_DENSE); + $this->SetBox(); + $this->SetMarginColor('white'); + } + + function SetDensity($aDense) { + $this->SetTickDensity(TICKD_NORMAL,$aDense); + } + + function SetClockwise($aFlg) { + $this->scale->SetClockwise($aFlg); + } + + function Set90AndMargin($lm=0,$rm=0,$tm=0,$bm=0) { + $adj = ($this->img->height - $this->img->width)/2; + $this->SetAngle(90); + $lm2 = -$adj + ($lm-$rm+$tm+$bm)/2; + $rm2 = -$adj + (-$lm+$rm+$tm+$bm)/2; + $tm2 = $adj + ($tm-$bm+$lm+$rm)/2; + $bm2 = $adj + (-$tm+$bm+$lm+$rm)/2; + $this->SetMargin($lm2, $rm2, $tm2, $bm2); + $this->axis->SetLabelAlign('right','center'); + } + + function SetScale($aScale,$rmax=0,$dummy1=1,$dummy2=1,$dummy3=1) { + if( $aScale == 'lin' ) { + $this->scale = new PolarScale($rmax,$this,$this->iClockwise); + } + elseif( $aScale == 'log' ) { + $this->scale = new PolarLogScale($rmax,$this,$this->iClockwise); + } + else { + JpGraphError::RaiseL(17004);//('Unknown scale type for polar graph. Must be "lin" or "log"'); + } + + $this->axis = new PolarAxis($this->img,$this->scale); + $this->SetMargin(40,40,50,40); + } + + function SetType($aType) { + $this->iType = $aType; + } + + function SetPlotSize($w,$h) { + $this->SetMargin(($this->img->width-$w)/2,($this->img->width-$w)/2, + ($this->img->height-$h)/2,($this->img->height-$h)/2); + } + + // Private methods + function GetPlotsMax() { + $n = count($this->plots); + $m = $this->plots[0]->Max(); + $i=1; + while($i < $n) { + $m = max($this->plots[$i]->Max(),$m); + ++$i; + } + return $m; + } + + function Stroke($aStrokeFileName="") { + + // Start by adjusting the margin so that potential titles will fit. + $this->AdjustMarginsForTitles(); + + // If the filename is the predefined value = '_csim_special_' + // we assume that the call to stroke only needs to do enough + // to correctly generate the CSIM maps. + // We use this variable to skip things we don't strictly need + // to do to generate the image map to improve performance + // a best we can. Therefor you will see a lot of tests !$_csim in the + // code below. + $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); + + // We need to know if we have stroked the plot in the + // GetCSIMareas. Otherwise the CSIM hasn't been generated + // and in the case of GetCSIM called before stroke to generate + // CSIM without storing an image to disk GetCSIM must call Stroke. + $this->iHasStroked = true; + + //Check if we should autoscale axis + if( !$this->scale->IsSpecified() && count($this->plots)>0 ) { + $max = $this->GetPlotsMax(); + $t1 = $this->img->plotwidth; + $this->img->plotwidth /= 2; + $t2 = $this->img->left_margin; + $this->img->left_margin += $this->img->plotwidth+1; + $this->scale->AutoScale($this->img,0,$max, + $this->img->plotwidth/$this->xtick_factor/2); + $this->img->plotwidth = $t1; + $this->img->left_margin = $t2; + } + else { + // The tick calculation will use the user suplied min/max values to determine + // the ticks. If auto_ticks is false the exact user specifed min and max + // values will be used for the scale. + // If auto_ticks is true then the scale might be slightly adjusted + // so that the min and max values falls on an even major step. + //$min = 0; + $max = $this->scale->scale[1]; + $t1 = $this->img->plotwidth; + $this->img->plotwidth /= 2; + $t2 = $this->img->left_margin; + $this->img->left_margin += $this->img->plotwidth+1; + $this->scale->AutoScale($this->img,0,$max, + $this->img->plotwidth/$this->xtick_factor/2); + $this->img->plotwidth = $t1; + $this->img->left_margin = $t2; + } + + if( $this->iType == POLAR_180 ) { + $pos = $this->img->height - $this->img->bottom_margin; + } + else { + $pos = $this->img->plotheight/2 + $this->img->top_margin; + } + + if( !$_csim ) { + $this->StrokePlotArea(); + } + + $this->iDoClipping = true; + + if( $this->iDoClipping ) { + $oldimage = $this->img->CloneCanvasH(); + } + + if( !$_csim ) { + $this->axis->StrokeGrid($pos); + } + + // Stroke all plots for Y1 axis + for($i=0; $i < count($this->plots); ++$i) { + $this->plots[$i]->Stroke($this->img,$this->scale); + } + + + if( $this->iDoClipping ) { + // Clipping only supports graphs at 0 and 90 degrees + if( $this->img->a == 0 ) { + $this->img->CopyCanvasH($oldimage,$this->img->img, + $this->img->left_margin,$this->img->top_margin, + $this->img->left_margin,$this->img->top_margin, + $this->img->plotwidth+1,$this->img->plotheight+1); + } + elseif( $this->img->a == 90 ) { + $adj1 = round(($this->img->height - $this->img->width)/2); + $adj2 = round(($this->img->width - $this->img->height)/2); + $lm = $this->img->left_margin; + $rm = $this->img->right_margin; + $tm = $this->img->top_margin; + $bm = $this->img->bottom_margin; + $this->img->CopyCanvasH($oldimage,$this->img->img, + $adj2 + round(($lm-$rm+$tm+$bm)/2), + $adj1 + round(($tm-$bm+$lm+$rm)/2), + $adj2 + round(($lm-$rm+$tm+$bm)/2), + $adj1 + round(($tm-$bm+$lm+$rm)/2), + $this->img->plotheight+1, + $this->img->plotwidth+1); + } + $this->img->Destroy(); + $this->img->SetCanvasH($oldimage); + } + + if( !$_csim ) { + $this->axis->Stroke($pos); + $this->axis->StrokeAngleLabels($pos,$this->iType); + } + + if( !$_csim ) { + $this->StrokePlotBox(); + $this->footer->Stroke($this->img); + + // The titles and legends never gets rotated so make sure + // that the angle is 0 before stroking them + $aa = $this->img->SetAngle(0); + $this->StrokeTitles(); + } + + for($i=0; $i < count($this->plots) ; ++$i ) { + $this->plots[$i]->Legend($this); + } + + $this->legend->Stroke($this->img); + + if( !$_csim ) { + + $this->StrokeTexts(); + $this->img->SetAngle($aa); + + // Draw an outline around the image map + if(_JPG_DEBUG) + $this->DisplayClientSideaImageMapAreas(); + + // If the filename is given as the special "__handle" + // then the image handler is returned and the image is NOT + // streamed back + if( $aStrokeFileName == _IMG_HANDLER ) { + return $this->img->img; + } + else { + // Finally stream the generated picture + $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); + } + } + } +} + + + +?> diff --git a/src/classes/jpgraph/jpgraph_radar.php b/src/classes/jpgraph/jpgraph_radar.php new file mode 100644 index 0000000..1d3de62 --- /dev/null +++ b/src/classes/jpgraph/jpgraph_radar.php @@ -0,0 +1,861 @@ +GetMinVal(); + $limit = $aScale->GetMaxVal(); + $nextMajor = 10*$start; + $step = $nextMajor / 10.0; + $count=1; + + $ticklen_maj=5; + $dx_maj=round(sin($aAxisAngle)*$ticklen_maj); + $dy_maj=round(cos($aAxisAngle)*$ticklen_maj); + $ticklen_min=3; + $dx_min=round(sin($aAxisAngle)*$ticklen_min); + $dy_min=round(cos($aAxisAngle)*$ticklen_min); + + $aMajPos=array(); + $aMajLabel=array(); + + if( $this->supress_first ) { + $aMajLabel[] = ''; + } + else { + $aMajLabel[]=$start; + } + + $yr=$aScale->RelTranslate($start); + $xt=round($yr*cos($aAxisAngle))+$aScale->scale_abs[0]; + $yt=$aPos-round($yr*sin($aAxisAngle)); + $aMajPos[]=$xt+2*$dx_maj; + $aMajPos[]=$yt-$aImg->GetFontheight()/2; + $grid[]=$xt; + $grid[]=$yt; + + $aImg->SetLineWeight($this->weight); + + for($y=$start; $y<=$limit; $y+=$step,++$count ) { + $yr=$aScale->RelTranslate($y); + $xt=round($yr*cos($aAxisAngle))+$aScale->scale_abs[0]; + $yt=$aPos-round($yr*sin($aAxisAngle)); + if( $count % 10 == 0 ) { + $grid[]=$xt; + $grid[]=$yt; + $aMajPos[]=$xt+2*$dx_maj; + $aMajPos[]=$yt-$aImg->GetFontheight()/2; + if( !$this->supress_tickmarks ) { + if( $this->majcolor != '' ) { + $aImg->PushColor($this->majcolor); + } + $aImg->Line($xt+$dx_maj,$yt+$dy_maj,$xt-$dx_maj,$yt-$dy_maj); + if( $this->majcolor != '' ) { + $aImg->PopColor(); + } + } + if( $this->label_formfunc != '' ) { + $f=$this->label_formfunc; + $l = call_user_func($f,$nextMajor); + } + else { + $l = $nextMajor; + } + + $aMajLabel[]=$l; + $nextMajor *= 10; + $step *= 10; + $count=1; + } + else { + if( !$this->supress_minor_tickmarks ) { + if( $this->mincolor != '' ) { + $aImg->PushColor($this->mincolor); + } + $aImg->Line($xt+$dx_min,$yt+$dy_min,$xt-$dx_min,$yt-$dy_min); + if( $this->mincolor != '' ) { + $aImg->PopColor(); + } + } + } + } + } +} + +//=================================================== +// CLASS RadarLinear +// Description: Linear ticks +//=================================================== +class RadarLinearTicks extends Ticks { + + private $minor_step=1, $major_step=2; + private $xlabel_offset=0,$xtick_offset=0; + + function __construct() { + // Empty + } + + // Return major step size in world coordinates + function GetMajor() { + return $this->major_step; + } + + // Return minor step size in world coordinates + function GetMinor() { + return $this->minor_step; + } + + // Set Minor and Major ticks (in world coordinates) + function Set($aMajStep,$aMinStep=false) { + if( $aMinStep==false ) { + $aMinStep=$aMajStep; + } + + if( $aMajStep <= 0 || $aMinStep <= 0 ) { + JpGraphError::RaiseL(25064); + //JpGraphError::Raise(" Minor or major step size is 0. Check that you haven't got an accidental SetTextTicks(0) in your code. If this is not the case you might have stumbled upon a bug in JpGraph. Please report this and if possible include the data that caused the problem."); + } + + $this->major_step=$aMajStep; + $this->minor_step=$aMinStep; + $this->is_set = true; + } + + function Stroke($aImg,&$grid,$aPos,$aAxisAngle,$aScale,&$aMajPos,&$aMajLabel) { + // Prepare to draw linear ticks + $maj_step_abs = abs($aScale->scale_factor*$this->major_step); + $min_step_abs = abs($aScale->scale_factor*$this->minor_step); + $nbrmaj = round($aScale->world_abs_size/$maj_step_abs); + $nbrmin = round($aScale->world_abs_size/$min_step_abs); + $skip = round($nbrmin/$nbrmaj); // Don't draw minor on top of major + + // Draw major ticks + $ticklen2=$this->major_abs_size; + $dx=round(sin($aAxisAngle)*$ticklen2); + $dy=round(cos($aAxisAngle)*$ticklen2); + $label=$aScale->scale[0]+$this->major_step; + + $aImg->SetLineWeight($this->weight); + + $aMajPos = array(); + $aMajLabel = array(); + + for($i=1; $i<=$nbrmaj; ++$i) { + $xt=round($i*$maj_step_abs*cos($aAxisAngle))+$aScale->scale_abs[0]; + $yt=$aPos-round($i*$maj_step_abs*sin($aAxisAngle)); + + if( $this->label_formfunc != '' ) { + $f=$this->label_formfunc; + $l = call_user_func($f,$label); + } + else { + $l = $label; + } + + $aMajLabel[]=$l; + $label += $this->major_step; + $grid[]=$xt; + $grid[]=$yt; + $aMajPos[($i-1)*2]=$xt+2*$dx; + $aMajPos[($i-1)*2+1]=$yt-$aImg->GetFontheight()/2; + if( !$this->supress_tickmarks ) { + if( $this->majcolor != '' ) { + $aImg->PushColor($this->majcolor); + } + $aImg->Line($xt+$dx,$yt+$dy,$xt-$dx,$yt-$dy); + if( $this->majcolor != '' ) { + $aImg->PopColor(); + } + } + } + + // Draw minor ticks + $ticklen2=$this->minor_abs_size; + $dx=round(sin($aAxisAngle)*$ticklen2); + $dy=round(cos($aAxisAngle)*$ticklen2); + if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { + if( $this->mincolor != '' ) { + $aImg->PushColor($this->mincolor); + } + for($i=1; $i<=$nbrmin; ++$i) { + if( ($i % $skip) == 0 ) { + continue; + } + $xt=round($i*$min_step_abs*cos($aAxisAngle))+$aScale->scale_abs[0]; + $yt=$aPos-round($i*$min_step_abs*sin($aAxisAngle)); + $aImg->Line($xt+$dx,$yt+$dy,$xt-$dx,$yt-$dy); + } + if( $this->mincolor != '' ) { + $aImg->PopColor(); + } + } + } +} + + +//=================================================== +// CLASS RadarAxis +// Description: Implements axis for the radar graph +//=================================================== +class RadarAxis extends AxisPrototype { + public $title=null; + private $title_color='navy'; + private $len=0; + + function __construct($img,$aScale,$color=array(0,0,0)) { + parent::__construct($img,$aScale,$color); + $this->len = $img->plotheight; + $this->title = new Text(); + $this->title->SetFont(FF_FONT1,FS_BOLD); + $this->color = array(0,0,0); + } + + // Stroke the axis + // $pos = Vertical position of axis + // $aAxisAngle = Axis angle + // $grid = Returns an array with positions used to draw the grid + // $lf = Label flag, TRUE if the axis should have labels + function Stroke($pos,$aAxisAngle,&$grid,$title,$lf) { + $this->img->SetColor($this->color); + + // Determine end points for the axis + $x=round($this->scale->world_abs_size*cos($aAxisAngle)+$this->scale->scale_abs[0]); + $y=round($pos-$this->scale->world_abs_size*sin($aAxisAngle)); + + // Draw axis + $this->img->SetColor($this->color); + $this->img->SetLineWeight($this->weight); + if( !$this->hide ) { + $this->img->Line($this->scale->scale_abs[0],$pos,$x,$y); + } + + $this->scale->ticks->Stroke($this->img,$grid,$pos,$aAxisAngle,$this->scale,$majpos,$majlabel); + $ncolor=0; + if( isset($this->ticks_label_colors) ) { + $ncolor=count($this->ticks_label_colors); + } + + // Draw labels + if( $lf && !$this->hide ) { + $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); + $this->img->SetTextAlign('left','top'); + $this->img->SetColor($this->label_color); + + // majpos contains (x,y) coordinates for labels + if( ! $this->hide_labels ) { + $n = floor(count($majpos)/2); + for($i=0; $i < $n; ++$i) { + // Set specific label color if specified + if( $ncolor > 0 ) { + $this->img->SetColor($this->ticks_label_colors[$i % $ncolor]); + } + + if( $this->ticks_label != null && isset($this->ticks_label[$i]) ) { + $this->img->StrokeText($majpos[$i*2],$majpos[$i*2+1],$this->ticks_label[$i]); + } + else { + $this->img->StrokeText($majpos[$i*2],$majpos[$i*2+1],$majlabel[$i]); + } + } + } + } + $this->_StrokeAxisTitle($pos,$aAxisAngle,$title); + } + + function _StrokeAxisTitle($pos,$aAxisAngle,$title) { + $this->title->Set($title); + $marg=6+$this->title->margin; + $xt=round(($this->scale->world_abs_size+$marg)*cos($aAxisAngle)+$this->scale->scale_abs[0]); + $yt=round($pos-($this->scale->world_abs_size+$marg)*sin($aAxisAngle)); + + // Position the axis title. + // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text + // that intersects with the extension of the corresponding axis. The code looks a little + // bit messy but this is really the only way of having a reasonable position of the + // axis titles. + if( $this->title->iWordwrap > 0 ) { + $title = wordwrap($title,$this->title->iWordwrap,"\n"); + } + + $h=$this->img->GetTextHeight($title)*1.2; + $w=$this->img->GetTextWidth($title)*1.2; + + while( $aAxisAngle > 2*M_PI ) + $aAxisAngle -= 2*M_PI; + + // Around 3 a'clock + if( $aAxisAngle>=7*M_PI/4 || $aAxisAngle <= M_PI/4 ) $dx=-0.15; // Small trimming to make the dist to the axis more even + + // Around 12 a'clock + if( $aAxisAngle>=M_PI/4 && $aAxisAngle <= 3*M_PI/4 ) $dx=($aAxisAngle-M_PI/4)*2/M_PI; + + // Around 9 a'clock + if( $aAxisAngle>=3*M_PI/4 && $aAxisAngle <= 5*M_PI/4 ) $dx=1; + + // Around 6 a'clock + if( $aAxisAngle>=5*M_PI/4 && $aAxisAngle <= 7*M_PI/4 ) $dx=(1-($aAxisAngle-M_PI*5/4)*2/M_PI); + + if( $aAxisAngle>=7*M_PI/4 ) $dy=(($aAxisAngle-M_PI)-3*M_PI/4)*2/M_PI; + if( $aAxisAngle<=M_PI/12 ) $dy=(0.5-$aAxisAngle*2/M_PI); + if( $aAxisAngle<=M_PI/4 && $aAxisAngle > M_PI/12) $dy=(1-$aAxisAngle*2/M_PI); + if( $aAxisAngle>=M_PI/4 && $aAxisAngle <= 3*M_PI/4 ) $dy=1; + if( $aAxisAngle>=3*M_PI/4 && $aAxisAngle <= 5*M_PI/4 ) $dy=(1-($aAxisAngle-3*M_PI/4)*2/M_PI); + if( $aAxisAngle>=5*M_PI/4 && $aAxisAngle <= 7*M_PI/4 ) $dy=0; + + if( !$this->hide ) { + $this->title->Stroke($this->img,$xt-$dx*$w,$yt-$dy*$h,$title); + } + } + +} // Class + + +//=================================================== +// CLASS RadarGrid +// Description: Draws grid for the radar graph +//=================================================== +class RadarGrid { //extends Grid { + private $type='solid'; + private $grid_color='#DDDDDD'; + private $show=false, $weight=1; + + function __construct() { + // Empty + } + + function SetColor($aMajColor) { + $this->grid_color = $aMajColor; + } + + function SetWeight($aWeight) { + $this->weight=$aWeight; + } + + // Specify if grid should be dashed, dotted or solid + function SetLineStyle($aType) { + $this->type = $aType; + } + + // Decide if both major and minor grid should be displayed + function Show($aShowMajor=true) { + $this->show=$aShowMajor; + } + + function Stroke($img,$grid) { + if( !$this->show ) { + return; + } + + $nbrticks = count($grid[0])/2; + $nbrpnts = count($grid); + $img->SetColor($this->grid_color); + $img->SetLineWeight($this->weight); + + for($i=0; $i<$nbrticks; ++$i) { + for($j=0; $j<$nbrpnts; ++$j) { + $pnts[$j*2]=$grid[$j][$i*2]; + $pnts[$j*2+1]=$grid[$j][$i*2+1]; + } + for($k=0; $k<$nbrpnts; ++$k ){ + $l=($k+1)%$nbrpnts; + if( $this->type == 'solid' ) + $img->Line($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1]); + elseif( $this->type == 'dotted' ) + $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],1,6); + elseif( $this->type == 'dashed' ) + $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],2,4); + elseif( $this->type == 'longdashed' ) + $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],8,6); + } + $pnts=array(); + } + } +} // Class + + +//=================================================== +// CLASS RadarPlot +// Description: Plot a radarplot +//=================================================== +class RadarPlot { + public $mark=null; + public $legend=''; + public $legendcsimtarget=''; + public $legendcsimalt=''; + public $csimtargets=array(); // Array of targets for CSIM + public $csimareas=""; // Resultant CSIM area tags + public $csimalts=null; // ALT:s for corresponding target + private $data=array(); + private $fill=false, $fill_color=array(200,170,180); + private $color=array(0,0,0); + private $weight=1; + private $linestyle='solid'; + + //--------------- + // CONSTRUCTOR + function __construct($data) { + $this->data = $data; + $this->mark = new PlotMark(); + } + + function Min() { + return Min($this->data); + } + + function Max() { + return Max($this->data); + } + + function SetLegend($legend) { + $this->legend=$legend; + } + + function SetLineStyle($aStyle) { + $this->linestyle=$aStyle; + } + + function SetLineWeight($w) { + $this->weight=$w; + } + + function SetFillColor($aColor) { + $this->fill_color = $aColor; + $this->fill = true; + } + + function SetFill($f=true) { + $this->fill = $f; + } + + function SetColor($aColor,$aFillColor=false) { + $this->color = $aColor; + if( $aFillColor ) { + $this->SetFillColor($aFillColor); + $this->fill = true; + } + } + + // Set href targets for CSIM + function SetCSIMTargets($aTargets,$aAlts=null) { + $this->csimtargets=$aTargets; + $this->csimalts=$aAlts; + } + + // Get all created areas + function GetCSIMareas() { + return $this->csimareas; + } + + function Stroke($img, $pos, $scale, $startangle) { + $nbrpnts = count($this->data); + $astep=2*M_PI/$nbrpnts; + $a=$startangle; + + for($i=0; $i<$nbrpnts; ++$i) { + + // Rotate each non null point to the correct axis-angle + $cs=$scale->RelTranslate($this->data[$i]); + $x=round($cs*cos($a)+$scale->scale_abs[0]); + $y=round($pos-$cs*sin($a)); + + $pnts[$i*2]=$x; + $pnts[$i*2+1]=$y; + + // If the next point is null then we draw this polygon segment + // to the center, skip the next and draw the next segment from + // the center up to the point on the axis with the first non-null + // value and continues from that point. Some additoinal logic is necessary + // to handle the boundary conditions + if( $i < $nbrpnts-1 ) { + if( is_null($this->data[$i+1]) ) { + $cs = 0; + $x=round($cs*cos($a)+$scale->scale_abs[0]); + $y=round($pos-$cs*sin($a)); + $pnts[$i*2]=$x; + $pnts[$i*2+1]=$y; + $a += $astep; + } + } + + $a += $astep; + } + + if( $this->fill ) { + $img->SetColor($this->fill_color); + $img->FilledPolygon($pnts); + } + + $img->SetLineWeight($this->weight); + $img->SetColor($this->color); + $img->SetLineStyle($this->linestyle); + $pnts[] = $pnts[0]; + $pnts[] = $pnts[1]; + $img->Polygon($pnts); + $img->SetLineStyle('solid'); // Reset line style to default + + // Add plotmarks on top + if( $this->mark->show ) { + for($i=0; $i < $nbrpnts; ++$i) { + if( isset($this->csimtargets[$i]) ) { + $this->mark->SetCSIMTarget($this->csimtargets[$i]); + $this->mark->SetCSIMAlt($this->csimalts[$i]); + $this->mark->SetCSIMAltVal($pnts[$i*2], $pnts[$i*2+1]); + $this->mark->Stroke($img, $pnts[$i*2], $pnts[$i*2+1]); + $this->csimareas .= $this->mark->GetCSIMAreas(); + } + else { + $this->mark->Stroke($img,$pnts[$i*2],$pnts[$i*2+1]); + } + } + } + + } + + function GetCount() { + return count($this->data); + } + + function Legend($graph) { + if( $this->legend == '' ) { + return; + } + if( $this->fill ) { + $graph->legend->Add($this->legend,$this->fill_color,$this->mark); + } else { + $graph->legend->Add($this->legend,$this->color,$this->mark); + } + } + +} // Class + +//=================================================== +// CLASS RadarGraph +// Description: Main container for a radar graph +//=================================================== +class RadarGraph extends Graph { + public $grid,$axis=null; + private $posx,$posy; + private $len; + private $axis_title=null; + + function __construct($width=300,$height=200,$cachedName="",$timeout=0,$inline=1) { + parent::__construct($width,$height,$cachedName,$timeout,$inline); + $this->posx = $width/2; + $this->posy = $height/2; + $this->len = min($width,$height)*0.35; + $this->SetColor(array(255,255,255)); + $this->SetTickDensity(TICKD_NORMAL); + $this->SetScale('lin'); + $this->SetGridDepth(DEPTH_FRONT); + } + + function HideTickMarks($aFlag=true) { + $this->axis->scale->ticks->SupressTickMarks($aFlag); + } + + function ShowMinorTickmarks($aFlag=true) { + $this->yscale->ticks->SupressMinorTickMarks(!$aFlag); + } + + function SetScale($axtype,$ymin=1,$ymax=1,$dummy1=null,$dumy2=null) { + if( $axtype != 'lin' && $axtype != 'log' ) { + JpGraphError::RaiseL(18003,$axtype); + //("Illegal scale for radarplot ($axtype). Must be \"lin\" or \"log\""); + } + if( $axtype == 'lin' ) { + $this->yscale = new LinearScale($ymin,$ymax); + $this->yscale->ticks = new RadarLinearTicks(); + $this->yscale->ticks->SupressMinorTickMarks(); + } + elseif( $axtype == 'log' ) { + $this->yscale = new LogScale($ymin,$ymax); + $this->yscale->ticks = new RadarLogTicks(); + } + + $this->axis = new RadarAxis($this->img,$this->yscale); + $this->grid = new RadarGrid(); + } + + function SetSize($aSize) { + if( $aSize < 0.1 || $aSize>1 ) { + JpGraphError::RaiseL(18004,$aSize); + //("Radar Plot size must be between 0.1 and 1. (Your value=$s)"); + } + $this->len=min($this->img->width,$this->img->height)*$aSize/2; + } + + function SetPlotSize($aSize) { + $this->SetSize($aSize); + } + + function SetTickDensity($densy=TICKD_NORMAL,$dummy1=null) { + $this->ytick_factor=25; + switch( $densy ) { + case TICKD_DENSE: + $this->ytick_factor=12; + break; + case TICKD_NORMAL: + $this->ytick_factor=25; + break; + case TICKD_SPARSE: + $this->ytick_factor=40; + break; + case TICKD_VERYSPARSE: + $this->ytick_factor=70; + break; + default: + JpGraphError::RaiseL(18005,$densy); + //("RadarPlot Unsupported Tick density: $densy"); + } + } + + function SetPos($px,$py=0.5) { + $this->SetCenter($px,$py); + } + + function SetCenter($px,$py=0.5) { + if( $px >= 0 && $px <= 1 ) { + $this->posx = $this->img->width*$px; + } + else { + $this->posx = $px; + } + if( $py >= 0 && $py <= 1 ) { + $this->posy = $this->img->height*$py; + } + else { + $this->posy = $py; + } + } + + function SetColor($aColor) { + $this->SetMarginColor($aColor); + } + + function SetTitles($aTitleArray) { + $this->axis_title = $aTitleArray; + } + + function Add($aPlot) { + if( $aPlot == null ) { + JpGraphError::RaiseL(25010);//("Graph::Add() You tried to add a null plot to the graph."); + } + if( is_array($aPlot) && count($aPlot) > 0 ) { + $cl = $aPlot[0]; + } + else { + $cl = $aPlot; + } + + if( $cl instanceof Text ) $this->AddText($aPlot); + elseif( class_exists('IconPlot',false) && ($cl instanceof IconPlot) ) $this->AddIcon($aPlot); + else { + $this->plots[] = $aPlot; + } + } + + function GetPlotsYMinMax($aPlots) { + $min=$aPlots[0]->Min(); + $max=$aPlots[0]->Max(); + foreach( $this->plots as $p ) { + $max=max($max,$p->Max()); + $min=min($min,$p->Min()); + } + if( $min < 0 ) { + JpGraphError::RaiseL(18006,$min); + //("Minimum data $min (Radar plots should only be used when all data points > 0)"); + } + return array($min,$max); + } + + function StrokeIcons() { + if( $this->iIcons != null ) { + $n = count($this->iIcons); + for( $i=0; $i < $n; ++$i ) { + $this->iIcons[$i]->Stroke($this->img); + } + } + } + + function StrokeTexts() { + if( $this->texts != null ) { + $n = count($this->texts); + for( $i=0; $i < $n; ++$i ) { + $this->texts[$i]->Stroke($this->img); + } + } + } + + // Stroke the Radar graph + function Stroke($aStrokeFileName='') { + + // If the filename is the predefined value = '_csim_special_' + // we assume that the call to stroke only needs to do enough + // to correctly generate the CSIM maps. + // We use this variable to skip things we don't strictly need + // to do to generate the image map to improve performance + // a best we can. Therefor you will see a lot of tests !$_csim in the + // code below. + $_csim = ( $aStrokeFileName === _CSIM_SPECIALFILE ); + + // We need to know if we have stroked the plot in the + // GetCSIMareas. Otherwise the CSIM hasn't been generated + // and in the case of GetCSIM called before stroke to generate + // CSIM without storing an image to disk GetCSIM must call Stroke. + $this->iHasStroked = true; + + $n = count($this->plots); + // Set Y-scale + + if( !$this->yscale->IsSpecified() && count($this->plots) > 0 ) { + list($min,$max) = $this->GetPlotsYMinMax($this->plots); + $this->yscale->AutoScale($this->img,0,$max,$this->len/$this->ytick_factor); + } + elseif( $this->yscale->IsSpecified() && + ( $this->yscale->auto_ticks || !$this->yscale->ticks->IsSpecified()) ) { + + // The tick calculation will use the user suplied min/max values to determine + // the ticks. If auto_ticks is false the exact user specifed min and max + // values will be used for the scale. + // If auto_ticks is true then the scale might be slightly adjusted + // so that the min and max values falls on an even major step. + $min = $this->yscale->scale[0]; + $max = $this->yscale->scale[1]; + $this->yscale->AutoScale($this->img,$min,$max, + $this->len/$this->ytick_factor, + $this->yscale->auto_ticks); + } + + // Set start position end length of scale (in absolute pixels) + $this->yscale->SetConstants($this->posx,$this->len); + + // We need as many axis as there are data points + $nbrpnts=$this->plots[0]->GetCount(); + + // If we have no titles just number the axis 1,2,3,... + if( $this->axis_title==null ) { + for($i=0; $i < $nbrpnts; ++$i ) { + $this->axis_title[$i] = $i+1; + } + } + elseif( count($this->axis_title) < $nbrpnts) { + JpGraphError::RaiseL(18007); + // ("Number of titles does not match number of points in plot."); + } + for( $i=0; $i < $n; ++$i ) { + if( $nbrpnts != $this->plots[$i]->GetCount() ) { + JpGraphError::RaiseL(18008); + //("Each radar plot must have the same number of data points."); + } + } + + if( !$_csim ) { + if( $this->background_image != '' ) { + $this->StrokeFrameBackground(); + } + else { + $this->StrokeFrame(); + $this->StrokeBackgroundGrad(); + } + } + $astep=2*M_PI/$nbrpnts; + + if( !$_csim ) { + if( $this->iIconDepth == DEPTH_BACK ) { + $this->StrokeIcons(); + } + + + // Prepare legends + for($i=0; $i < $n; ++$i) { + $this->plots[$i]->Legend($this); + } + $this->legend->Stroke($this->img); + $this->footer->Stroke($this->img); + } + + if( !$_csim ) { + if( $this->grid_depth == DEPTH_BACK ) { + // Draw axis and grid + for( $i=0,$a=M_PI/2; $i < $nbrpnts; ++$i, $a += $astep ) { + $this->axis->Stroke($this->posy,$a,$grid[$i],$this->axis_title[$i],$i==0); + } + $this->grid->Stroke($this->img,$grid); + } + if( $this->iIconDepth == DEPTH_BACK ) { + $this->StrokeIcons(); + } + + } + + // Plot points + $a=M_PI/2; + for($i=0; $i < $n; ++$i ) { + $this->plots[$i]->Stroke($this->img, $this->posy, $this->yscale, $a); + } + + if( !$_csim ) { + if( $this->grid_depth != DEPTH_BACK ) { + // Draw axis and grid + for( $i=0,$a=M_PI/2; $i < $nbrpnts; ++$i, $a += $astep ) { + $this->axis->Stroke($this->posy,$a,$grid[$i],$this->axis_title[$i],$i==0); + } + $this->grid->Stroke($this->img,$grid); + } + + $this->StrokeTitles(); + $this->StrokeTexts(); + if( $this->iIconDepth == DEPTH_FRONT ) { + $this->StrokeIcons(); + } + } + + // Should we do any final image transformation + if( $this->iImgTrans && !$_csim ) { + if( !class_exists('ImgTrans',false) ) { + require_once('jpgraph_imgtrans.php'); + } + + $tform = new ImgTrans($this->img->img); + $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, + $this->iImgTransDirection,$this->iImgTransHighQ, + $this->iImgTransMinSize,$this->iImgTransFillColor, + $this->iImgTransBorder); + } + + if( !$_csim ) { + // If the filename is given as the special "__handle" + // then the image handler is returned and the image is NOT + // streamed back + if( $aStrokeFileName == _IMG_HANDLER ) { + return $this->img->img; + } + else { + // Finally stream the generated picture + $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); + } + } + } +} // Class + +/* EOF */ +?> diff --git a/src/classes/jpgraph/jpgraph_regstat.php b/src/classes/jpgraph/jpgraph_regstat.php new file mode 100644 index 0000000..0f6c96b --- /dev/null +++ b/src/classes/jpgraph/jpgraph_regstat.php @@ -0,0 +1,215 @@ +y2 = array(); + $this->xdata = $xdata; + $this->ydata = $ydata; + + $n = count($ydata); + $this->n = $n; + if( $this->n !== count($xdata) ) { + JpGraphError::RaiseL(19001); + //('Spline: Number of X and Y coordinates must be the same'); + } + + // Natural spline 2:derivate == 0 at endpoints + $this->y2[0] = 0.0; + $this->y2[$n-1] = 0.0; + $delta[0] = 0.0; + + // Calculate 2:nd derivate + for($i=1; $i < $n-1; ++$i) { + $d = ($xdata[$i+1]-$xdata[$i-1]); + if( $d == 0 ) { + JpGraphError::RaiseL(19002); + //('Invalid input data for spline. Two or more consecutive input X-values are equal. Each input X-value must differ since from a mathematical point of view it must be a one-to-one mapping, i.e. each X-value must correspond to exactly one Y-value.'); + } + $s = ($xdata[$i]-$xdata[$i-1])/$d; + $p = $s*$this->y2[$i-1]+2.0; + $this->y2[$i] = ($s-1.0)/$p; + $delta[$i] = ($ydata[$i+1]-$ydata[$i])/($xdata[$i+1]-$xdata[$i]) - + ($ydata[$i]-$ydata[$i-1])/($xdata[$i]-$xdata[$i-1]); + $delta[$i] = (6.0*$delta[$i]/($xdata[$i+1]-$xdata[$i-1])-$s*$delta[$i-1])/$p; + } + + // Backward substitution + for( $j=$n-2; $j >= 0; --$j ) { + $this->y2[$j] = $this->y2[$j]*$this->y2[$j+1] + $delta[$j]; + } + } + + // Return the two new data vectors + function Get($num=50) { + $n = $this->n ; + $step = ($this->xdata[$n-1]-$this->xdata[0]) / ($num-1); + $xnew=array(); + $ynew=array(); + $xnew[0] = $this->xdata[0]; + $ynew[0] = $this->ydata[0]; + for( $j=1; $j < $num; ++$j ) { + $xnew[$j] = $xnew[0]+$j*$step; + $ynew[$j] = $this->Interpolate($xnew[$j]); + } + return array($xnew,$ynew); + } + + // Return a single interpolated Y-value from an x value + function Interpolate($xpoint) { + + $max = $this->n-1; + $min = 0; + + // Binary search to find interval + while( $max-$min > 1 ) { + $k = ($max+$min) / 2; + if( $this->xdata[$k] > $xpoint ) + $max=$k; + else + $min=$k; + } + + // Each interval is interpolated by a 3:degree polynom function + $h = $this->xdata[$max]-$this->xdata[$min]; + + if( $h == 0 ) { + JpGraphError::RaiseL(19002); + //('Invalid input data for spline. Two or more consecutive input X-values are equal. Each input X-value must differ since from a mathematical point of view it must be a one-to-one mapping, i.e. each X-value must correspond to exactly one Y-value.'); + } + + + $a = ($this->xdata[$max]-$xpoint)/$h; + $b = ($xpoint-$this->xdata[$min])/$h; + return $a*$this->ydata[$min]+$b*$this->ydata[$max]+ + (($a*$a*$a-$a)*$this->y2[$min]+($b*$b*$b-$b)*$this->y2[$max])*($h*$h)/6.0; + } +} + +//------------------------------------------------------------------------ +// CLASS Bezier +// Create a new data array from a number of control points +//------------------------------------------------------------------------ +class Bezier { + /** + * @author Thomas Despoix, openXtrem company + * @license released under QPL + * @abstract Bezier interoplated point generation, + * computed from control points data sets, based on Paul Bourke algorithm : + * http://local.wasp.uwa.edu.au/~pbourke/geometry/bezier/index2.html + */ + private $datax = array(); + private $datay = array(); + private $n=0; + + function __construct($datax, $datay, $attraction_factor = 1) { + // Adding control point multiple time will raise their attraction power over the curve + $this->n = count($datax); + if( $this->n !== count($datay) ) { + JpGraphError::RaiseL(19003); + //('Bezier: Number of X and Y coordinates must be the same'); + } + $idx=0; + foreach($datax as $datumx) { + for ($i = 0; $i < $attraction_factor; $i++) { + $this->datax[$idx++] = $datumx; + } + } + $idx=0; + foreach($datay as $datumy) { + for ($i = 0; $i < $attraction_factor; $i++) { + $this->datay[$idx++] = $datumy; + } + } + $this->n *= $attraction_factor; + } + + /** + * Return a set of data points that specifies the bezier curve with $steps points + * @param $steps Number of new points to return + * @return array($datax, $datay) + */ + function Get($steps) { + $datax = array(); + $datay = array(); + for ($i = 0; $i < $steps; $i++) { + list($datumx, $datumy) = $this->GetPoint((double) $i / (double) $steps); + $datax[$i] = $datumx; + $datay[$i] = $datumy; + } + + $datax[] = end($this->datax); + $datay[] = end($this->datay); + + return array($datax, $datay); + } + + /** + * Return one point on the bezier curve. $mu is the position on the curve where $mu is in the + * range 0 $mu < 1 where 0 is tha start point and 1 is the end point. Note that every newly computed + * point depends on all the existing points + * + * @param $mu Position on the bezier curve + * @return array($x, $y) + */ + function GetPoint($mu) { + $n = $this->n - 1; + $k = 0; + $kn = 0; + $nn = 0; + $nkn = 0; + $blend = 0.0; + $newx = 0.0; + $newy = 0.0; + + $muk = 1.0; + $munk = (double) pow(1-$mu,(double) $n); + + for ($k = 0; $k <= $n; $k++) { + $nn = $n; + $kn = $k; + $nkn = $n - $k; + $blend = $muk * $munk; + $muk *= $mu; + $munk /= (1-$mu); + while ($nn >= 1) { + $blend *= $nn; + $nn--; + if ($kn > 1) { + $blend /= (double) $kn; + $kn--; + } + if ($nkn > 1) { + $blend /= (double) $nkn; + $nkn--; + } + } + $newx += $this->datax[$k] * $blend; + $newy += $this->datay[$k] * $blend; + } + + return array($newx, $newy); + } +} + +// EOF +?> diff --git a/src/classes/jpgraph/jpgraph_rgb.inc.php b/src/classes/jpgraph/jpgraph_rgb.inc.php index 2cbc85b..5389261 100644 --- a/src/classes/jpgraph/jpgraph_rgb.inc.php +++ b/src/classes/jpgraph/jpgraph_rgb.inc.php @@ -6,7 +6,7 @@ // Created: 2001-01-08 (Refactored to separate file 2008-08-01) // Ver: $Id: jpgraph_rgb.inc.php 1893 2009-10-02 23:15:25Z ljp $ // -// Copyright (c) Aditus Consulting. All rights reserved. +// Copyright (c) Asial Corporation. All rights reserved. //======================================================================== diff --git a/src/classes/jpgraph/jpgraph_scatter.php b/src/classes/jpgraph/jpgraph_scatter.php new file mode 100644 index 0000000..fe987c2 --- /dev/null +++ b/src/classes/jpgraph/jpgraph_scatter.php @@ -0,0 +1,242 @@ +iSize = $aSize; + $this->iArrowSize = $aArrowSize; + } + + function SetColor($aColor) { + $this->iColor = $aColor; + } + + function Stroke($aImg,$x,$y,$a) { + // First rotate the center coordinates + list($x,$y) = $aImg->Rotate($x,$y); + + $old_origin = $aImg->SetCenter($x,$y); + $old_a = $aImg->a; + $aImg->SetAngle(-$a+$old_a); + + $dx = round($this->iSize/2); + $c = array($x-$dx,$y,$x+$dx,$y); + $x += $dx; + + list($dx,$dy) = $this->isizespec[$this->iArrowSize]; + $ca = array($x,$y,$x-$dx,$y-$dy,$x-$dx,$y+$dy,$x,$y); + + $aImg->SetColor($this->iColor); + $aImg->Polygon($c); + $aImg->FilledPolygon($ca); + + $aImg->SetCenter($old_origin[0],$old_origin[1]); + $aImg->SetAngle($old_a); + } +} + +//=================================================== +// CLASS FieldPlot +// Description: Render a field plot +//=================================================== +class FieldPlot extends Plot { + public $arrow = ''; + private $iAngles = array(); + private $iCallback = ''; + + function __construct($datay,$datax,$angles) { + if( (count($datax) != count($datay)) ) + JpGraphError::RaiseL(20001);//("Fieldplots must have equal number of X and Y points."); + if( (count($datax) != count($angles)) ) + JpGraphError::RaiseL(20002);//("Fieldplots must have an angle specified for each X and Y points."); + + $this->iAngles = $angles; + + parent::__construct($datay,$datax); + $this->value->SetAlign('center','center'); + $this->value->SetMargin(15); + + $this->arrow = new FieldArrow(); + } + + function SetCallback($aFunc) { + $this->iCallback = $aFunc; + } + + function Stroke($img,$xscale,$yscale) { + + // Remeber base color and size + $bc = $this->arrow->iColor; + $bs = $this->arrow->iSize; + $bas = $this->arrow->iArrowSize; + + for( $i=0; $i<$this->numpoints; ++$i ) { + // Skip null values + if( $this->coords[0][$i]==="" ) + continue; + + $f = $this->iCallback; + if( $f != "" ) { + list($cc,$cs,$cas) = call_user_func($f,$this->coords[1][$i],$this->coords[0][$i],$this->iAngles[$i]); + // Fall back on global data if the callback isn't set + if( $cc == "" ) $cc = $bc; + if( $cs == "" ) $cs = $bs; + if( $cas == "" ) $cas = $bas; + $this->arrow->SetColor($cc); + $this->arrow->SetSize($cs,$cas); + } + + $xt = $xscale->Translate($this->coords[1][$i]); + $yt = $yscale->Translate($this->coords[0][$i]); + + $this->arrow->Stroke($img,$xt,$yt,$this->iAngles[$i]); + $this->value->Stroke($img,$this->coords[0][$i],$xt,$yt); + } + } + + // Framework function + function Legend($aGraph) { + if( $this->legend != "" ) { + $aGraph->legend->Add($this->legend,$this->mark->fill_color,$this->mark,0, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + } +} + +//=================================================== +// CLASS ScatterPlot +// Description: Render X and Y plots +//=================================================== +class ScatterPlot extends Plot { + public $mark,$link; + private $impuls = false; + //--------------- + // CONSTRUCTOR + function __construct($datay,$datax=false) { + if( (count($datax) != count($datay)) && is_array($datax)) { + JpGraphError::RaiseL(20003);//("Scatterplot must have equal number of X and Y points."); + } + parent::__construct($datay,$datax); + $this->mark = new PlotMark(); + $this->mark->SetType(MARK_SQUARE); + $this->mark->SetColor($this->color); + $this->value->SetAlign('center','center'); + $this->value->SetMargin(0); + $this->link = new LineProperty(1,'black','solid'); + $this->link->iShow = false; + } + + //--------------- + // PUBLIC METHODS + function SetImpuls($f=true) { + $this->impuls = $f; + } + + function SetStem($f=true) { + $this->impuls = $f; + } + + // Combine the scatter plot points with a line + function SetLinkPoints($aFlag=true,$aColor="black",$aWeight=1,$aStyle='solid') { + $this->link->iShow = $aFlag; + $this->link->iColor = $aColor; + $this->link->iWeight = $aWeight; + $this->link->iStyle = $aStyle; + } + + function Stroke($img,$xscale,$yscale) { + + $ymin=$yscale->scale_abs[0]; + if( $yscale->scale[0] < 0 ) + $yzero=$yscale->Translate(0); + else + $yzero=$yscale->scale_abs[0]; + + $this->csimareas = ''; + for( $i=0; $i<$this->numpoints; ++$i ) { + + // Skip null values + if( $this->coords[0][$i]==='' || $this->coords[0][$i]==='-' || $this->coords[0][$i]==='x') + continue; + + if( isset($this->coords[1]) ) + $xt = $xscale->Translate($this->coords[1][$i]); + else + $xt = $xscale->Translate($i); + $yt = $yscale->Translate($this->coords[0][$i]); + + + if( $this->link->iShow && isset($yt_old) ) { + $img->SetColor($this->link->iColor); + $img->SetLineWeight($this->link->iWeight); + $old = $img->SetLineStyle($this->link->iStyle); + $img->StyleLine($xt_old,$yt_old,$xt,$yt); + $img->SetLineStyle($old); + } + + if( $this->impuls ) { + $img->SetColor($this->color); + $img->SetLineWeight($this->weight); + $img->Line($xt,$yzero,$xt,$yt); + } + + if( !empty($this->csimtargets[$i]) ) { + if( !empty($this->csimwintargets[$i]) ) { + $this->mark->SetCSIMTarget($this->csimtargets[$i],$this->csimwintargets[$i]); + } + else { + $this->mark->SetCSIMTarget($this->csimtargets[$i]); + } + $this->mark->SetCSIMAlt($this->csimalts[$i]); + } + + if( isset($this->coords[1]) ) { + $this->mark->SetCSIMAltVal($this->coords[0][$i],$this->coords[1][$i]); + } + else { + $this->mark->SetCSIMAltVal($this->coords[0][$i],$i); + } + + $this->mark->Stroke($img,$xt,$yt); + + $this->csimareas .= $this->mark->GetCSIMAreas(); + $this->value->Stroke($img,$this->coords[0][$i],$xt,$yt); + + $xt_old = $xt; + $yt_old = $yt; + } + } + + // Framework function + function Legend($aGraph) { + if( $this->legend != "" ) { + $aGraph->legend->Add($this->legend,$this->mark->fill_color,$this->mark,0, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + } +} // Class +/* EOF */ +?> diff --git a/src/classes/jpgraph/jpgraph_stock.php b/src/classes/jpgraph/jpgraph_stock.php new file mode 100644 index 0000000..88c4208 --- /dev/null +++ b/src/classes/jpgraph/jpgraph_stock.php @@ -0,0 +1,198 @@ +iTupleSize ) { + JpGraphError::RaiseL(21001,$this->iTupleSize); + //('Data values for Stock charts must contain an even multiple of '.$this->iTupleSize.' data points.'); + } + parent::__construct($datay,$datax); + $this->numpoints /= $this->iTupleSize; + } + //--------------- + // PUBLIC METHODS + + function SetColor($aColor,$aColor1='white',$aColor2='darkred',$aColor3='darkred') { + $this->color = $aColor; + $this->iStockColor1 = $aColor1; + $this->iStockColor2 = $aColor2; + $this->iStockColor3 = $aColor3; + } + + function SetWidth($aWidth) { + // Make sure it's odd + $this->iWidth = 2*floor($aWidth/2)+1; + } + + function HideEndLines($aHide=true) { + $this->iEndLines = !$aHide; + } + + // Gets called before any axis are stroked + function PreStrokeAdjust($graph) { + if( $this->center ) { + $a=0.5; $b=0.5; + $this->numpoints++; + } else { + $a=0; $b=0; + } + $graph->xaxis->scale->ticks->SetXLabelOffset($a); + $graph->SetTextScaleOff($b); + } + + // Method description + function Stroke($img,$xscale,$yscale) { + $n=$this->numpoints; + if( $this->center ) $n--; + if( isset($this->coords[1]) ) { + if( count($this->coords[1])!=$n ) { + JpGraphError::RaiseL(2003,count($this->coords[1]),$n); + // ("Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])." Number of Y-points:$numpoints"); + } + else { + $exist_x = true; + } + } + else { + $exist_x = false; + } + + if( $exist_x ) { + $xs=$this->coords[1][0]; + } + else { + $xs=0; + } + + $ts = $this->iTupleSize; + $this->csimareas = ''; + for( $i=0; $i<$n; ++$i) { + + //If value is NULL, then don't draw a bar at all + if ($this->coords[0][$i*$ts] === null) continue; + + if( $exist_x ) { + $x=$this->coords[1][$i]; + if ($x === null) continue; + } + else { + $x=$i; + } + $xt = $xscale->Translate($x); + + $neg = $this->coords[0][$i*$ts] > $this->coords[0][$i*$ts+1] ; + $yopen = $yscale->Translate($this->coords[0][$i*$ts]); + $yclose = $yscale->Translate($this->coords[0][$i*$ts+1]); + $ymin = $yscale->Translate($this->coords[0][$i*$ts+2]); + $ymax = $yscale->Translate($this->coords[0][$i*$ts+3]); + + $dx = floor($this->iWidth/2); + $xl = $xt - $dx; + $xr = $xt + $dx; + + if( $neg ) { + $img->SetColor($this->iStockColor3); + } + else { + $img->SetColor($this->iStockColor1); + } + $img->FilledRectangle($xl,$yopen,$xr,$yclose); + $img->SetLineWeight($this->weight); + if( $neg ) { + $img->SetColor($this->iStockColor2); + } + else { + $img->SetColor($this->color); + } + + $img->Rectangle($xl,$yopen,$xr,$yclose); + + if( $yopen < $yclose ) { + $ytop = $yopen ; + $ybottom = $yclose ; + } + else { + $ytop = $yclose ; + $ybottom = $yopen ; + } + $img->SetColor($this->color); + $img->Line($xt,$ytop,$xt,$ymax); + $img->Line($xt,$ybottom,$xt,$ymin); + + if( $this->iEndLines ) { + $img->Line($xl,$ymax,$xr,$ymax); + $img->Line($xl,$ymin,$xr,$ymin); + } + + // A chance for subclasses to add things to the bar + // for data point i + $this->ModBox($img,$xscale,$yscale,$i,$xl,$xr,$neg); + + // Setup image maps + if( !empty($this->csimtargets[$i]) ) { + $this->csimareas.= 'csimareas .= ' href="'.$this->csimtargets[$i].'"'; + if( !empty($this->csimalts[$i]) ) { + $sval=$this->csimalts[$i]; + $this->csimareas .= " title=\"$sval\" alt=\"$sval\" "; + } + $this->csimareas.= " />\n"; + } + } + return true; + } + + // A hook for subclasses to modify the plot + function ModBox($img,$xscale,$yscale,$i,$xl,$xr,$neg) {} + +} // Class + +//=================================================== +// CLASS BoxPlot +//=================================================== +class BoxPlot extends StockPlot { + private $iPColor='black',$iNColor='white'; + + function __construct($datay,$datax=false) { + $this->iTupleSize=5; + parent::__construct($datay,$datax); + } + + function SetMedianColor($aPos,$aNeg) { + $this->iPColor = $aPos; + $this->iNColor = $aNeg; + } + + function ModBox($img,$xscale,$yscale,$i,$xl,$xr,$neg) { + if( $neg ) + $img->SetColor($this->iNColor); + else + $img->SetColor($this->iPColor); + + $y = $yscale->Translate($this->coords[0][$i*5+4]); + $img->Line($xl,$y,$xr,$y); + } +} + +/* EOF */ +?> diff --git a/src/classes/jpgraph/jpgraph_table.php b/src/classes/jpgraph/jpgraph_table.php new file mode 100644 index 0000000..852d78b --- /dev/null +++ b/src/classes/jpgraph/jpgraph_table.php @@ -0,0 +1,1325 @@ +iVal = new Text($aVal); + $this->iRow = $aRow; + $this->iCol = $aCol; + $this->iPRow = $aRow; // Initialiy each cell is its own parent + $this->iPCol = $aCol; + $this->iIconConstrain = array(-1,-1); + } + + function Init($aTable) { + $this->iTable = $aTable; + } + + function SetCSIMTarget($aTarget,$aAlt='',$aWinTarget='') { + $this->iCSIMtarget = $aTarget; + $this->iCSIMwintarget = $aWinTarget; + $this->iCSIMalt = $aAlt; + } + + function GetCSIMArea() { + if( $this->iCSIMtarget !== '' ) + return $this->iCSIMArea; + else + return ''; + } + + function SetImageConstrain($aType,$aVal) { + if( !in_array($aType,array(TIMG_WIDTH, TIMG_HEIGHT)) ) { + JpGraphError::RaiseL(27015); + } + $this->iIconConstrain = array($aType,$aVal); + } + + function SetCountryFlag($aFlag,$aScale=1.0,$aMix=100,$aStdSize=3) { + $this->iIcon = new IconPlot(); + $this->iIcon->SetCountryFlag($aFlag,0,0,$aScale,$aMix,$aStdSize); + } + + function SetImage($aFile,$aScale=1.0,$aMix=100) { + $this->iIcon = new IconPlot($aFile,0,0,$aScale,$aMix); + } + + function SetImageFromString($aStr,$aScale=1.0,$aMix=100) { + $this->iIcon = new IconPlot("",0,0,$aScale,$aMix); + $this->iIcon->CreateFromString($aStr); + } + + function SetRowColSpan($aRowSpan,$aColSpan) { + $this->iRowSpan = $aRowSpan; + $this->iColSpan = $aColSpan; + $this->iMerged = true; + } + + function SetMerged($aPRow,$aPCol,$aFlg=true) { + $this->iMerged = $aFlg; + $this->iPRow=$aPRow; + $this->iPCol=$aPCol; + } + + function IsMerged() { + return $this->iMerged; + } + + function SetNumberFormat($aF) { + $this->iNumberFormat = $aF; + } + + function Set($aTxt) { + $this->iVal->Set($aTxt); + } + + function SetFont($aFF,$aFS,$aFSize) { + $this->iFF = $aFF; + $this->iFS = $aFS; + $this->iFSize = $aFSize; + $this->iVal->SetFont($aFF,$aFS,$aFSize); + } + + function SetFillColor($aColor) { + $this->iBGColor=$aColor; + } + + function SetFontColor($aColor) { + $this->iFontColor=$aColor; + } + + function SetGridColor($aLeft,$aTop=null,$aBottom=null,$aRight=null) { + if( $aLeft !== null ) $this->iGridColor[0] = $aLeft; + if( $aTop !== null ) $this->iGridColor[1] = $aTop; + if( $aBottom !== null ) $this->iGridColor[2] = $aBottom; + if( $aRight !== null )$this->iGridColor[3] = $aRight; + } + + function SetGridStyle($aLeft,$aTop=null,$aBottom=null,$aRight=null) { + if( $aLeft !== null ) $this->iGridStyle[0] = $aLeft; + if( $aTop !== null ) $this->iGridStyle[1] = $aTop; + if( $aBottom !== null ) $this->iGridStyle[2] = $aBottom; + if( $aRight !== null )$this->iGridStyle[3] = $aRight; + } + + function SetGridWeight($aLeft=null,$aTop=null,$aBottom=null,$aRight=null) { + if( $aLeft !== null ) $this->iGridWeight[0] = $aLeft; + if( $aTop !== null ) $this->iGridWeight[1] = $aTop; + if( $aBottom !== null ) $this->iGridWeight[2] = $aBottom; + if( $aRight !== null ) $this->iGridWeight[3] = $aRight; + } + + function SetMargin($aLeft,$aRight,$aTop,$aBottom) { + $this->iMarginLeft=$aLeft; + $this->iMarginRight=$aRight; + $this->iMarginTop=$aTop; + $this->iMarginBottom=$aBottom; + } + + function GetWidth($aImg) { + if( $this->iIcon !== null ) { + if( $this->iIconConstrain[0] == TIMG_WIDTH ) { + $this->iIcon->SetScale(1); + $tmp = $this->iIcon->GetWidthHeight(); + $this->iIcon->SetScale($this->iIconConstrain[1]/$tmp[0]); + } + elseif( $this->iIconConstrain[0] == TIMG_HEIGHT ) { + $this->iIcon->SetScale(1); + $tmp = $this->iIcon->GetWidthHeight(); + $this->iIcon->SetScale($this->iIconConstrain[1]/$tmp[1]); + } + $tmp = $this->iIcon->GetWidthHeight(); + $iwidth = $tmp[0]; + } + else { + $iwidth=0; + } + if( $this->iTable->iCells[$this->iPRow][$this->iPCol]->iVal->dir == 0 ) { + $pwidth = $this->iTable->iCells[$this->iPRow][$this->iPCol]->iVal->GetWidth($aImg); + } + elseif( $this->iTable->iCells[$this->iPRow][$this->iPCol]->iVal->dir == 90 ) { + $pwidth = $this->iTable->iCells[$this->iPRow][$this->iPCol]->iVal->GetFontHeight($aImg)+2; + } + else { + $pwidth = $this->iTable->iCells[$this->iPRow][$this->iPCol]->iVal->GetWidth($aImg)+2; + } + + $pcolspan = $this->iTable->iCells[$this->iPRow][$this->iPCol]->iColSpan; + return round(max($iwidth,$pwidth)/$pcolspan) + $this->iMarginLeft + $this->iMarginRight; + } + + function GetHeight($aImg) { + if( $this->iIcon !== null ) { + if( $this->iIconConstrain[0] == TIMG_WIDTH ) { + $this->iIcon->SetScale(1); + $tmp = $this->iIcon->GetWidthHeight(); + $this->iIcon->SetScale($this->iIconConstrain[1]/$tmp[0]); + } + elseif( $this->iIconConstrain[0] == TIMG_HEIGHT ) { + $this->iIcon->SetScale(1); + $tmp = $this->iIcon->GetWidthHeight(); + $this->iIcon->SetScale($this->iIconConstrain[1]/$tmp[1]); + } + $tmp = $this->iIcon->GetWidthHeight(); + $iheight = $tmp[1]; + } + else { + $iheight = 0; + } + if( $this->iTable->iCells[$this->iPRow][$this->iPCol]->iVal->dir == 0 ) { + $pheight = $this->iTable->iCells[$this->iPRow][$this->iPCol]->iVal->GetHeight($aImg); + } + else { + $pheight = $this->iTable->iCells[$this->iPRow][$this->iPCol]->iVal->GetHeight($aImg)+1; + } + $prowspan = $this->iTable->iCells[$this->iPRow][$this->iPCol]->iRowSpan; + return round(max($iheight,$pheight)/$prowspan) + $this->iMarginTop + $this->iMarginBottom; + } + + function SetAlign($aHorAlign='left',$aVertAlign='bottom') { + $aHorAlign = strtolower($aHorAlign); + $aVertAlign = strtolower($aVertAlign); + $chk = array('left','right','center','bottom','top','middle'); + if( !in_array($aHorAlign,$chk) || !in_array($aVertAlign,$chk) ) { + JpGraphError::RaiseL(27011,$aHorAlign,$aVertAlign); + } + $this->iVertAlign = $aVertAlign; + $this->iHorAlign = $aHorAlign; + } + + function AdjustMarginsForGrid() { + if( $this->iCol > 0 ) { + switch( $this->iGridStyle[0] ) { + case TGRID_SINGLE: $wf=1; break; + case TGRID_DOUBLE: $wf=3; break; + case TGRID_DOUBLE2: $wf=4; break; + } + $this->iMarginLeft += $this->iGridWeight[0]*$wf; + } + if( $this->iRow > 0 ) { + switch( $this->iGridStyle[1] ) { + case TGRID_SINGLE: $wf=1; break; + case TGRID_DOUBLE: $wf=3; break; + case TGRID_DOUBLE2: $wf=4; break; + } + $this->iMarginTop += $this->iGridWeight[1]*$wf; + } + if( $this->iRow+$this->iRowSpan-1 < $this->iTable->iSize[0]-1 ) { + switch( $this->iGridStyle[2] ) { + case TGRID_SINGLE: $wf=1; break; + case TGRID_DOUBLE: $wf=3; break; + case TGRID_DOUBLE2: $wf=4; break; + } + $this->iMarginBottom += $this->iGridWeight[2]*$wf; + } + if( $this->iCol+$this->iColSpan-1 < $this->iTable->iSize[1]-1 ) { + switch( $this->iGridStyle[3] ) { + case TGRID_SINGLE: $wf=1; break; + case TGRID_DOUBLE: $wf=3; break; + case TGRID_DOUBLE2: $wf=4; break; + } + $this->iMarginRight += $this->iGridWeight[3]*$wf; + } + } + + function StrokeVGrid($aImg,$aX,$aY,$aWidth,$aHeight,$aDir=1) { + // Left or right grid line + // For the right we increase the X-pos and for the right we decrease it. This is + // determined by the direction argument. + $idx = $aDir==1 ? 0 : 3; + + // We don't stroke the grid lines that are on the edge of the table since this is + // the place of the border. + if( ( ($this->iCol > 0 && $idx==0) || ($this->iCol+$this->iColSpan-1 < $this->iTable->iSize[1]-1 && $idx==3) ) + && $this->iGridWeight[$idx] > 0 ) { + $x = $aDir==1 ? $aX : $aX + $aWidth-1; + $y = $aY+$aHeight-1; + $aImg->SetColor($this->iGridColor[$idx]); + switch( $this->iGridStyle[$idx] ) { + case TGRID_SINGLE: + for( $i=0; $i < $this->iGridWeight[$idx]; ++$i ) + $aImg->Line($x+$i*$aDir,$aY, $x+$i*$aDir,$y); + break; + + case TGRID_DOUBLE: + for( $i=0; $i < $this->iGridWeight[$idx]; ++$i ) + $aImg->Line($x+$i*$aDir,$aY, $x+$i*$aDir,$y); + $x += $this->iGridWeight[$idx]*2; + for( $i=0; $i < $this->iGridWeight[$idx]; ++$i ) + $aImg->Line($x+$i*$aDir,$aY, $x+$i*$aDir,$y); + break; + + case TGRID_DOUBLE2: + for( $i=0; $i < $this->iGridWeight[$idx]*2; ++$i ) + $aImg->Line($x+$i*$aDir,$aY,$x+$i*$aDir,$y); + $x += $this->iGridWeight[$idx]*3; + for( $i=0; $i < $this->iGridWeight[$idx]; ++$i ) + $aImg->Line($x+$i*$aDir,$aY, $x+$i*$aDir,$y); + break; + } + } + } + + function StrokeHGrid($aImg,$aX,$aY,$aWidth,$aHeight,$aDir=1) { + // Top or bottom grid line + // For the left we increase the X-pos and for the right we decrease it. This is + // determined by the direction argument. + $idx = $aDir==1 ? 1 : 2; + + // We don't stroke the grid lines that are on the edge of the table since this is + // the place of the border. + if( ( ($this->iRow > 0 && $idx==1) || ($this->iRow+$this->iRowSpan-1 < $this->iTable->iSize[0]-1 && $idx==2) ) + && $this->iGridWeight[$idx] > 0) { + $y = $aDir==1 ? $aY : $aY+$aHeight-1; + $x = $aX+$aWidth-1; + $aImg->SetColor($this->iGridColor[$idx]); + switch( $this->iGridStyle[$idx] ) { + case TGRID_SINGLE: + for( $i=0; $i < $this->iGridWeight[$idx]; ++$i ) + $aImg->Line($aX,$y+$i, $x,$y+$i); + break; + + case TGRID_DOUBLE: + for( $i=0; $i < $this->iGridWeight[$idx]; ++$i ) + $aImg->Line($aX,$y+$i, $x,$y+$i); + $y += $this->iGridWeight[$idx]*2; + for( $i=0; $i < $this->iGridWeight[$idx]; ++$i ) + $aImg->Line($aX,$y+$i, $x,$y+$i); + break; + + case TGRID_DOUBLE2: + for( $i=0; $i < $this->iGridWeight[$idx]*2; ++$i ) + $aImg->Line($aX,$y+$i, $x,$y+$i); + $y += $this->iGridWeight[$idx]*3; + for( $i=0; $i < $this->iGridWeight[$idx]; ++$i ) + $aImg->Line($aX,$y+$i, $x,$y+$i); + break; + } + } + } + + function Stroke($aImg,$aX,$aY,$aWidth,$aHeight) { + // If this is a merged cell we only stroke if it is the parent cell. + // The parent cell holds the merged cell block + if( $this->iMerged && ($this->iRow != $this->iPRow || $this->iCol != $this->iPCol) ) { + return; + } + + if( $this->iBGColor != '' ) { + $aImg->SetColor($this->iBGColor); + $aImg->FilledRectangle($aX,$aY,$aX+$aWidth-1,$aY+$aHeight-1); + } + + $coords = $aX.','.$aY.','.($aX+$aWidth-1).','.$aY.','.($aX+$aWidth-1).','.($aY+$aHeight-1).','.$aX.','.($aY+$aHeight-1); + if( ! empty($this->iCSIMtarget) ) { + $this->iCSIMArea = 'iCSIMwintarget) ) { + $this->iCSIMArea .= " target=\"".$this->iCSIMwintarget."\""; + } + if( ! empty($this->iCSIMalt) ) { + $this->iCSIMArea .= ' alt="'.$this->iCSIMalt.'" title="'.$this->iCSIMalt."\" "; + } + $this->iCSIMArea .= " />\n"; + } + + $this->StrokeVGrid($aImg,$aX,$aY,$aWidth,$aHeight); + $this->StrokeVGrid($aImg,$aX,$aY,$aWidth,$aHeight,-1); + $this->StrokeHGrid($aImg,$aX,$aY,$aWidth,$aHeight); + $this->StrokeHGrid($aImg,$aX,$aY,$aWidth,$aHeight,-1); + + if( $this->iIcon !== null ) { + switch( $this->iHorAlign ) { + case 'left': + $x = $aX+$this->iMarginLeft; + $hanchor='left'; + break; + case 'center': + case 'middle': + $x = $aX+$this->iMarginLeft+round(($aWidth-$this->iMarginLeft-$this->iMarginRight)/2); + $hanchor='center'; + break; + case 'right': + $x = $aX+$aWidth-$this->iMarginRight-1; + $hanchor='right'; + break; + default: + JpGraphError::RaiseL(27012,$this->iHorAlign); + } + + switch( $this->iVertAlign ) { + case 'top': + $y = $aY+$this->iMarginTop; + $vanchor='top'; + break; + case 'center': + case 'middle': + $y = $aY+$this->iMarginTop+round(($aHeight-$this->iMarginTop-$this->iMarginBottom)/2); + $vanchor='center'; + break; + case 'bottom': + $y = $aY+$aHeight-1-$this->iMarginBottom; + $vanchor='bottom'; + break; + default: + JpGraphError::RaiseL(27012,$this->iVertAlign); + } + $this->iIcon->SetAnchor($hanchor,$vanchor); + $this->iIcon->_Stroke($aImg,$x,$y); + } + $this->iVal->SetColor($this->iFontColor); + $this->iVal->SetFont($this->iFF,$this->iFS,$this->iFSize); + switch( $this->iHorAlign ) { + case 'left': + $x = $aX+$this->iMarginLeft; + break; + case 'center': + case 'middle': + $x = $aX+$this->iMarginLeft+round(($aWidth-$this->iMarginLeft-$this->iMarginRight)/2); + break; + case 'right': + $x = $aX+$aWidth-$this->iMarginRight-1; + break; + default: + JpGraphError::RaiseL(27012,$this->iHorAlign); + } + // A workaround for the shortcomings in the TTF font handling in GD + // The anchor position for rotated text (=90) is to "short" so we add + // an offset based on the actual font size + if( $this->iVal->dir != 0 && $this->iVal->font_family >= 10 ) { + $aY += 4 + round($this->iVal->font_size*0.8); + } + switch( $this->iVertAlign ) { + case 'top': + $y = $aY+$this->iMarginTop; + break; + case 'center': + case 'middle': + $y = $aY+$this->iMarginTop+round(($aHeight-$this->iMarginTop-$this->iMarginBottom)/2); + //$y -= round($this->iVal->GetFontHeight($aImg)/2); + $y -= round($this->iVal->GetHeight($aImg)/2); + break; + case 'bottom': + //$y = $aY+$aHeight-1-$this->iMarginBottom-$this->iVal->GetFontHeight($aImg); + $y = $aY+$aHeight-$this->iMarginBottom-$this->iVal->GetHeight($aImg); + break; + default: + JpGraphError::RaiseL(27012,$this->iVertAlign); + } + $this->iVal->SetAlign($this->iHorAlign,'top'); + if( $this->iNumberFormat !== null && is_numeric($this->iVal->t) ) { + $this->iVal->t = sprintf($this->iNumberFormat,$this->iVal->t); + } + $this->iVal->Stroke($aImg,$x,$y); + } +} + +//--------------------------------------------------------------------- +// CLASS GTextTable +// Description: +// Graphic text table +//--------------------------------------------------------------------- +class GTextTable { + public $iCells = array(), $iSize=array(0,0); // Need to be public since they are used by the cell + private $iWidth=0, $iHeight=0; + private $iColWidth=NULL,$iRowHeight=NULL; + private $iImg=NULL; + private $iXPos=0, $iYPos=0; + private $iScaleXPos=null,$iScaleYPos=null; + private $iBGColor=''; + private $iBorderColor='black',$iBorderWeight=1; + private $iInit=false; + private $iYAnchor='top',$iXAnchor='left'; + /*----------------------------------------------------------------- + * First and second phase constructors + *----------------------------------------------------------------- + */ + function __construct() { + // Empty + } + + function Init($aRows=0,$aCols=0,$aFillText='') { + $this->iSize[0] = $aRows; + $this->iSize[1] = $aCols; + for($i=0; $i < $this->iSize[0]; ++$i) { + for($j=0; $j < $this->iSize[1]; ++$j) { + $this->iCells[$i][$j] = new GTextTableCell($aFillText,$i,$j); + $this->iCells[$i][$j]->Init($this); + } + } + $this->iInit=true; + } + + /*----------------------------------------------------------------- + * Outer border of table + *----------------------------------------------------------------- + */ + function SetBorder($aWeight=1,$aColor='black') { + $this->iBorderColor=$aColor; + $this->iBorderWeight = $aWeight; + } + + + /*----------------------------------------------------------------- + * Position in graph of table + *----------------------------------------------------------------- + */ + function SetPos($aX,$aY) { + $this->iXPos = $aX; + $this->iYPos = $aY; + } + + function SetScalePos($aX,$aY) { + $this->iScaleXPos = $aX; + $this->iScaleYPos = $aY; + } + + function SetAnchorPos($aXAnchor,$aYAnchor='top') { + $this->iXAnchor = $aXAnchor; + $this->iYAnchor = $aYAnchor; + } + + /*----------------------------------------------------------------- + * Setup country flag in a cell + *----------------------------------------------------------------- + */ + function SetCellCountryFlag($aRow,$aCol,$aFlag,$aScale=1.0,$aMix=100,$aStdSize=3) { + $this->_chkR($aRow); + $this->_chkC($aCol); + $this->iCells[$aRow][$aCol]->SetCountryFlag($aFlag,$aScale,$aMix,$aStdSize); + + } + + /*----------------------------------------------------------------- + * Setup image in a cell + *----------------------------------------------------------------- + */ + function SetCellImage($aRow,$aCol,$aFile,$aScale=1.0,$aMix=100) { + $this->_chkR($aRow); + $this->_chkC($aCol); + $this->iCells[$aRow][$aCol]->SetImage($aFile,$aScale,$aMix); + } + + function SetRowImage($aRow,$aFile,$aScale=1.0,$aMix=100) { + $this->_chkR($aRow); + for($j=0; $j < $this->iSize[1]; ++$j) { + $this->iCells[$aRow][$j]->SetImage($aFile,$aScale,$aMix); + } + } + + function SetColImage($aCol,$aFile,$aScale=1.0,$aMix=100) { + $this->_chkC($aCol); + for($j=0; $j < $this->iSize[0]; ++$j) { + $this->iCells[$j][$aCol]->SetImage($aFile,$aScale,$aMix); + } + } + + function SetImage($aFileR1,$aScaleC1=null,$aMixR2=null,$aC2=null,$aFile=null,$aScale=1.0,$aMix=100) { + if( $aScaleC1 !== null && $aMixR2!==null && $aC2!==null && $aFile!==null ) { + $this->_chkR($aArgR1); $this->_chkC($aC1); + $this->_chkR($aR2); $this->_chkC($aC2); + } + else { + if( $aScaleC1 !== null ) $aScale = $aScaleC1; + if( $aMixR2 !== null ) $aMix = $aMixR2; + $aFile = $aFileR1; + $aMixR2 = $this->iSize[0]-1; $aFileR1 = 0; + $aC2 = $this->iSize[1]-1; $aScaleC1 = 0; + } + for($i=$aArgR1; $i <= $aR2; ++$i) { + for($j=$aC1; $j <= $aC2; ++$j) { + $this->iCells[$i][$j]->SetImage($aFile,$aScale,$aMix); + } + } + } + + function SetCellImageConstrain($aRow,$aCol,$aType,$aVal) { + $this->_chkR($aRow); + $this->_chkC($aCol); + $this->iCells[$aRow][$aCol]->SetImageConstrain($aType,$aVal); + } + + /*----------------------------------------------------------------- + * Generate a HTML version of the table + *----------------------------------------------------------------- + */ + function toString() { + $t = ''; + for($i=0; $i < $this->iSize[0]; ++$i) { + $t .= ''; + for($j=0; $j < $this->iSize[1]; ++$j) { + $t .= ''; + } + $t .= ''; + } + $t .= '
'; + if( $this->iCells[$i][$j]->iMerged ) + $t .= 'M '; + $t .= 'val='.$this->iCells[$i][$j]->iVal->t; + $t .= ' (cs='.$this->iCells[$i][$j]->iColSpan. + ', rs='.$this->iCells[$i][$j]->iRowSpan.')'; + $t .= '
'; + return $t; + } + + /*----------------------------------------------------------------- + * Specify data for table + *----------------------------------------------------------------- + */ + function Set($aArg1,$aArg2=NULL,$aArg3=NULL) { + if( $aArg2===NULL && $aArg3===NULL ) { + if( is_array($aArg1) ) { + if( is_array($aArg1[0]) ) { + $m = count($aArg1); + // Find the longest row + $n=0; + for($i=0; $i < $m; ++$i) + $n = max(count($aArg1[$i]),$n); + for($i=0; $i < $m; ++$i) { + for($j=0; $j < $n; ++$j) { + if( isset($aArg1[$i][$j]) ){ + $this->_setcell($i,$j,(string)$aArg1[$i][$j]); + } + else { + $this->_setcell($i,$j); + } + } + } + $this->iSize[0] = $m; + $this->iSize[1] = $n; + $this->iInit=true; + } + else { + JpGraphError::RaiseL(27001); + //('Illegal argument to GTextTable::Set(). Array must be 2 dimensional'); + } + } + else { + JpGraphError::RaiseL(27002); + //('Illegal argument to GTextTable::Set()'); + } + } + else { + // Must be in the form (row,col,val) + $this->_chkR($aArg1); + $this->_chkC($aArg2); + $this->_setcell($aArg1,$aArg2,(string)$aArg3); + } + } + + /*--------------------------------------------------------------------- + * Cell margin setting + *--------------------------------------------------------------------- + */ + function SetPadding($aArgR1,$aC1=null,$aR2=null,$aC2=null,$aPad=null) { + if( $aC1 !== null && $aR2!==null && $aC2!==null && $aPad!==null ) { + $this->_chkR($aArgR1); $this->_chkC($aC1); + $this->_chkR($aR2); $this->_chkC($aC2); + } + else { + $aPad = $aArgR1; + $aR2 = $this->iSize[0]-1; $aArgR1 = 0; + $aC2 = $this->iSize[1]-1; $aC1 = 0; + } + for($i=$aArgR1; $i <= $aR2; ++$i) { + for($j=$aC1; $j <= $aC2; ++$j) { + $this->iCells[$i][$j]->SetMargin($aPad,$aPad,$aPad,$aPad); + } + } + } + + function SetRowPadding($aRow,$aPad) { + $this->_chkR($aRow); + for($j=0; $j < $this->iSize[1]; ++$j) { + $this->iCells[$aRow][$j]->SetMargin($aPad,$aPad,$aPad,$aPad); + } + } + + function SetColPadding($aCol,$aPad) { + $this->_chkC($aCol); + for($j=0; $j < $this->iSize[0]; ++$j) { + $this->iCells[$j][$aCol]->SetMargin($aPad,$aPad,$aPad,$aPad); + } + } + + function SetCellPadding($aRow,$aCol,$aPad) { + $this->_chkR($aRow); + $this->_chkC($aCol); + $this->iCells[$aRow][$aCol]->SetMargin($aPad,$aPad,$aPad,$aPad); + } + + + /*--------------------------------------------------------------------- + * Cell text orientation setting + *--------------------------------------------------------------------- + */ + function SetTextOrientation($aArgR1,$aC1=null,$aR2=null,$aC2=null,$aO=null) { + if( $aC1 !== null && $aR2!==null && $aC2!==null && $aPad!==null ) { + $this->_chkR($aArgR1); $this->_chkC($aC1); + $this->_chkR($aR2); $this->_chkC($aC2); + } + else { + $aO = $aArgR1; + $aR2 = $this->iSize[0]-1; $aArgR1 = 0; + $aC2 = $this->iSize[1]-1; $aC1 = 0; + } + for($i=$aArgR1; $i <= $aR2; ++$i) { + for($j=$aC1; $j <= $aC2; ++$j) { + $this->iCells[$i][$j]->iVal->SetOrientation($aO); + } + } + } + + function SetRowTextOrientation($aRow,$aO) { + $this->_chkR($aRow); + for($j=0; $j < $this->iSize[1]; ++$j) { + $this->iCells[$aRow][$j]->iVal->SetOrientation($aO); + } + } + + function SetColTextOrientation($aCol,$aO) { + $this->_chkC($aCol); + for($j=0; $j < $this->iSize[0]; ++$j) { + $this->iCells[$j][$aCol]->iVal->SetOrientation($aO); + } + } + + function SetCellTextOrientation($aRow,$aCol,$aO) { + $this->_chkR($aRow); + $this->_chkC($aCol); + $this->iCells[$aRow][$aCol]->iVal->SetOrientation($aO); + } + + + + + /*--------------------------------------------------------------------- + * Font color setting + *--------------------------------------------------------------------- + */ + + function SetColor($aArgR1,$aC1=null,$aR2=null,$aC2=null,$aArg=null) { + if( $aC1 !== null && $aR2!==null && $aC2!==null && $aArg!==null ) { + $this->_chkR($aArgR1); $this->_chkC($aC1); + $this->_chkR($aR2); $this->_chkC($aC2); + } + else { + $aArg = $aArgR1; + $aR2 = $this->iSize[0]-1; $aArgR1 = 0; + $aC2 = $this->iSize[1]-1; $aC1 = 0; + } + for($i=$aArgR1; $i <= $aR2; ++$i) { + for($j=$aC1; $j <= $aC2; ++$j) { + $this->iCells[$i][$j]->SetFontColor($aArg); + } + } + } + + function SetRowColor($aRow,$aColor) { + $this->_chkR($aRow); + for($j=0; $j < $this->iSize[1]; ++$j) { + $this->iCells[$aRow][$j]->SetFontColor($aColor); + } + } + + function SetColColor($aCol,$aColor) { + $this->_chkC($aCol); + for($i=0; $i < $this->iSize[0]; ++$i) { + $this->iCells[$i][$aCol]->SetFontColor($aColor); + } + } + + function SetCellColor($aRow,$aCol,$aColor) { + $this->_chkR($aRow); + $this->_chkC($aCol); + $this->iCells[$aRow][$aCol]->SetFontColor($aColor); + } + + /*--------------------------------------------------------------------- + * Fill color settings + *--------------------------------------------------------------------- + */ + + function SetFillColor($aArgR1,$aC1=null,$aR2=null,$aC2=null,$aArg=null) { + if( $aC1 !== null && $aR2!==null && $aC2!==null && $aArg!==null ) { + $this->_chkR($aArgR1); $this->_chkC($aC1); + $this->_chkR($aR2); $this->_chkC($aC2); + for($i=$aArgR1; $i <= $aR2; ++$i) { + for($j=$aC1; $j <= $aC2; ++$j) { + $this->iCells[$i][$j]->SetFillColor($aArg); + } + } + } + else { + $this->iBGColor = $aArgR1; + } + } + + function SetRowFillColor($aRow,$aColor) { + $this->_chkR($aRow); + for($j=0; $j < $this->iSize[1]; ++$j) { + $this->iCells[$aRow][$j]->SetFillColor($aColor); + } + } + + function SetColFillColor($aCol,$aColor) { + $this->_chkC($aCol); + for($i=0; $i < $this->iSize[0]; ++$i) { + $this->iCells[$i][$aCol]->SetFillColor($aColor); + } + } + + function SetCellFillColor($aRow,$aCol,$aColor) { + $this->_chkR($aRow); + $this->_chkC($aCol); + $this->iCells[$aRow][$aCol]->SetFillColor($aColor); + } + + /*--------------------------------------------------------------------- + * Font family setting + *--------------------------------------------------------------------- + */ + function SetFont() { + $numargs = func_num_args(); + if( $numargs == 2 || $numargs == 3 ) { + $aFF = func_get_arg(0); + $aFS = func_get_arg(1); + if( $numargs == 3 ) + $aFSize=func_get_arg(2); + else + $aFSize=10; + $aR2 = $this->iSize[0]-1; $aR1 = 0; + $aC2 = $this->iSize[1]-1; $aC1 = 0; + + } + elseif($numargs == 6 || $numargs == 7 ) { + $aR1 = func_get_arg(0); $aC1 = func_get_arg(1); + $aR2 = func_get_arg(2); $aC2 = func_get_arg(3); + $aFF = func_get_arg(4); $aFS = func_get_arg(5); + if( $numargs == 7 ) + $aFSize=func_get_arg(6); + else + $aFSize=10; + } + else { + JpGraphError::RaiseL(27003); + //('Wrong number of arguments to GTextTable::SetColor()'); + } + $this->_chkR($aR1); $this->_chkC($aC1); + $this->_chkR($aR2); $this->_chkC($aC2); + for($i=$aR1; $i <= $aR2; ++$i) { + for($j=$aC1; $j <= $aC2; ++$j) { + $this->iCells[$i][$j]->SetFont($aFF,$aFS,$aFSize); + } + } + } + + function SetRowFont($aRow,$aFF,$aFS,$aFSize=10) { + $this->_chkR($aRow); + for($j=0; $j < $this->iSize[1]; ++$j) { + $this->iCells[$aRow][$j]->SetFont($aFF,$aFS,$aFSize); + } + } + + function SetColFont($aCol,$aFF,$aFS,$aFSize=10) { + $this->_chkC($aCol); + for($i=0; $i < $this->iSize[0]; ++$i) { + $this->iCells[$i][$aCol]->SetFont($aFF,$aFS,$aFSize); + } + } + + function SetCellFont($aRow,$aCol,$aFF,$aFS,$aFSize=10) { + $this->_chkR($aRow); + $this->_chkC($aCol); + $this->iCells[$aRow][$aCol]->SetFont($aFF,$aFS,$aFSize); + } + + /*--------------------------------------------------------------------- + * Cell align settings + *--------------------------------------------------------------------- + */ + + function SetAlign($aR1HAlign=null,$aC1VAlign=null,$aR2=null,$aC2=null,$aHArg=null,$aVArg='center') { + if( $aC1VAlign !== null && $aR2!==null && $aC2!==null && $aHArg!==null ) { + $this->_chkR($aR1HAlign); $this->_chkC($aC1VAlign); + $this->_chkR($aR2); $this->_chkC($aC2); + } + else { + if( $aR1HAlign === null ) { + JpGraphError::RaiseL(27010); + } + if( $aC1VAlign === null ) { + $aC1VAlign = 'center'; + } + $aHArg = $aR1HAlign; + $aVArg = $aC1VAlign === null ? 'center' : $aC1VAlign ; + $aR2 = $this->iSize[0]-1; $aR1HAlign = 0; + $aC2 = $this->iSize[1]-1; $aC1VAlign = 0; + } + for($i=$aR1HAlign; $i <= $aR2; ++$i) { + for($j=$aC1VAlign; $j <= $aC2; ++$j) { + $this->iCells[$i][$j]->SetAlign($aHArg,$aVArg); + } + } + } + + function SetCellAlign($aRow,$aCol,$aHorAlign,$aVertAlign='bottom') { + $this->_chkR($aRow); + $this->_chkC($aCol); + $this->iCells[$aRow][$aCol]->SetAlign($aHorAlign,$aVertAlign); + } + + function SetRowAlign($aRow,$aHorAlign,$aVertAlign='bottom') { + $this->_chkR($aRow); + for($j=0; $j < $this->iSize[1]; ++$j) { + $this->iCells[$aRow][$j]->SetAlign($aHorAlign,$aVertAlign); + } + } + + function SetColAlign($aCol,$aHorAlign,$aVertAlign='bottom') { + $this->_chkC($aCol); + for($i=0; $i < $this->iSize[0]; ++$i) { + $this->iCells[$i][$aCol]->SetAlign($aHorAlign,$aVertAlign); + } + } + + /*--------------------------------------------------------------------- + * Cell number format + *--------------------------------------------------------------------- + */ + + function SetNumberFormat($aArgR1,$aC1=null,$aR2=null,$aC2=null,$aArg=null) { + if( $aC1 !== null && $aR2!==null && $aC2!==null && $aArg!==null ) { + $this->_chkR($aArgR1); $this->_chkC($aC1); + $this->_chkR($aR2); $this->_chkC($aC2); + } + else { + $aArg = $aArgR1; + $aR2 = $this->iSize[0]-1; $aArgR1 = 0; + $aC2 = $this->iSize[1]-1; $aC1 = 0; + } + if( !is_string($aArg) ) { + JpGraphError::RaiseL(27013); // argument must be a string + } + for($i=$aArgR1; $i <= $aR2; ++$i) { + for($j=$aC1; $j <= $aC2; ++$j) { + $this->iCells[$i][$j]->SetNumberFormat($aArg); + } + } + } + + function SetRowNumberFormat($aRow,$aF) { + $this->_chkR($aRow); + if( !is_string($aF) ) { + JpGraphError::RaiseL(27013); // argument must be a string + } + for($j=0; $j < $this->iSize[1]; ++$j) { + $this->iCells[$aRow][$j]->SetNumberFormat($aF); + } + } + + function SetColNumberFormat($aCol,$aF) { + $this->_chkC($aCol); + if( !is_string($aF) ) { + JpGraphError::RaiseL(27013); // argument must be a string + } + for($i=0; $i < $this->iSize[0]; ++$i) { + $this->iCells[$i][$aCol]->SetNumberFormat($aF); + } + } + + function SetCellNumberFormat($aRow,$aCol,$aF) { + $this->_chkR($aRow); $this->_chkC($aCol); + if( !is_string($aF) ) { + JpGraphError::RaiseL(27013); // argument must be a string + } + $this->iCells[$aRow][$aCol]->SetNumberFormat($aF); + } + + /*--------------------------------------------------------------------- + * Set row and column min size + *--------------------------------------------------------------------- + */ + + function SetMinColWidth($aColWidth,$aWidth=null) { + // If there is only one argument this means that all + // columns get set to the same width + if( $aWidth===null ) { + for($i=0; $i < $this->iSize[1]; ++$i) { + $this->iColWidth[$i] = $aColWidth; + } + } + else { + $this->_chkC($aColWidth); + $this->iColWidth[$aColWidth] = $aWidth; + } + } + + function SetMinRowHeight($aRowHeight,$aHeight=null) { + // If there is only one argument this means that all + // rows get set to the same height + if( $aHeight===null ) { + for($i=0; $i < $this->iSize[0]; ++$i) { + $this->iRowHeight[$i] = $aRowHeight; + } + } + else { + $this->_chkR($aRowHeight); + $this->iRowHeight[$aRowHeight] = $aHeight; + } + } + + /*--------------------------------------------------------------------- + * Grid line settings + *--------------------------------------------------------------------- + */ + + function SetGrid($aWeight=1,$aColor='black',$aStyle=TGRID_SINGLE) { + $rc = $this->iSize[0]; + $cc = $this->iSize[1]; + for($i=0; $i < $rc; ++$i) { + for($j=0; $j < $cc; ++$j) { + $this->iCells[$i][$j]->SetGridColor($aColor,$aColor); + $this->iCells[$i][$j]->SetGridWeight($aWeight,$aWeight); + $this->iCells[$i][$j]->SetGridStyle($aStyle); + } + } + } + + function SetColGrid($aCol,$aWeight=1,$aColor='black',$aStyle=TGRID_SINGLE) { + $this->_chkC($aCol); + for($i=0; $i < $this->iSize[0]; ++$i) { + $this->iCells[$i][$aCol]->SetGridWeight($aWeight); + $this->iCells[$i][$aCol]->SetGridColor($aColor); + $this->iCells[$i][$aCol]->SetGridStyle($aStyle); + } + } + + function SetRowGrid($aRow,$aWeight=1,$aColor='black',$aStyle=TGRID_SINGLE) { + $this->_chkR($aRow); + for($j=0; $j < $this->iSize[1]; ++$j) { + $this->iCells[$aRow][$j]->SetGridWeight(NULL,$aWeight); + $this->iCells[$aRow][$j]->SetGridColor(NULL,$aColor); + $this->iCells[$aRow][$j]->SetGridStyle(NULL,$aStyle); + } + } + + /*--------------------------------------------------------------------- + * Merge cells + *--------------------------------------------------------------------- + */ + + function MergeRow($aRow,$aHAlign='center',$aVAlign='center') { + $this->_chkR($aRow); + $this->MergeCells($aRow,0,$aRow,$this->iSize[1]-1,$aHAlign,$aVAlign); + } + + function MergeCol($aCol,$aHAlign='center',$aVAlign='center') { + $this->_chkC($aCol); + $this->MergeCells(0,$aCol,$this->iSize[0]-1,$aCol,$aHAlign,$aVAlign); + } + + function MergeCells($aR1,$aC1,$aR2,$aC2,$aHAlign='center',$aVAlign='center') { + if( $aR1 > $aR2 || $aC1 > $aC2 ) { + JpGraphError::RaiseL(27004); + //('GTextTable::MergeCells(). Specified cell range to be merged is not valid.'); + } + $this->_chkR($aR1); $this->_chkC($aC1); + $this->_chkR($aR2); $this->_chkC($aC2); + $rspan = $aR2-$aR1+1; + $cspan = $aC2-$aC1+1; + // Setup the parent cell for this merged group + if( $this->iCells[$aR1][$aC1]->IsMerged() ) { + JpGraphError::RaiseL(27005,$aR1,$aC1,$aR2,$aC2); + //("Cannot merge already merged cells in the range ($aR1,$aC1), ($aR2,$aC2)"); + } + $this->iCells[$aR1][$aC1]->SetRowColSpan($rspan,$cspan); + $this->iCells[$aR1][$aC1]->SetAlign($aHAlign,$aVAlign); + for($i=$aR1; $i <= $aR2; ++$i) { + for($j=$aC1; $j <= $aC2; ++$j) { + if( ! ($i == $aR1 && $j == $aC1) ) { + if( $this->iCells[$i][$j]->IsMerged() ) { + JpGraphError::RaiseL(27005,$aR1,$aC1,$aR2,$aC2); + //("Cannot merge already merged cells in the range ($aR1,$aC1), ($aR2,$aC2)"); + } + $this->iCells[$i][$j]->SetMerged($aR1,$aC1,true); + } + } + } + } + + + /*--------------------------------------------------------------------- + * CSIM methods + *--------------------------------------------------------------------- + */ + + function SetCSIMTarget($aTarget,$aAlt=null,$aAutoTarget=false) { + $m = $this->iSize[0]; + $n = $this->iSize[1]; + $csim = ''; + for($i=0; $i < $m; ++$i) { + for($j=0; $j < $n; ++$j) { + if( $aAutoTarget ) + $t = $aTarget."?row=$i&col=$j"; + else + $t = $aTarget; + $this->iCells[$i][$j]->SetCSIMTarget($t,$aAlt); + } + } + } + + function SetCellCSIMTarget($aRow,$aCol,$aTarget,$aAlt=null) { + $this->_chkR($aRow); + $this->_chkC($aCol); + $this->iCells[$aRow][$aCol]->SetCSIMTarget($aTarget,$aAlt); + } + + /*--------------------------------------------------------------------- + * Private methods + *--------------------------------------------------------------------- + */ + + function GetCSIMAreas() { + $m = $this->iSize[0]; + $n = $this->iSize[1]; + $csim = ''; + for($i=0; $i < $m; ++$i) { + for($j=0; $j < $n; ++$j) { + $csim .= $this->iCells[$i][$j]->GetCSIMArea(); + } + } + return $csim; + } + + function _chkC($aCol) { + if( ! $this->iInit ) { + JpGraphError::Raise(27014); // Table not initialized + } + if( $aCol < 0 || $aCol >= $this->iSize[1] ) + JpGraphError::RaiseL(27006,$aCol); + //("GTextTable:\nColumn argument ($aCol) is outside specified table size."); + } + + function _chkR($aRow) { + if( ! $this->iInit ) { + JpGraphError::Raise(27014); // Table not initialized + } + if( $aRow < 0 || $aRow >= $this->iSize[0] ) + JpGraphError::RaiseL(27007,$aRow); + //("GTextTable:\nRow argument ($aRow) is outside specified table size."); + } + + function _getScalePos() { + if( $this->iScaleXPos === null || $this->iScaleYPos === null ) { + return false; + } + return array($this->iScaleXPos, $this->iScaleYPos); + } + + function _autoSizeTable($aImg) { + // Get maximum column width and row height + $m = $this->iSize[0]; + $n = $this->iSize[1]; + $w=1;$h=1; + + // Get maximum row height per row + for($i=0; $i < $m; ++$i) { + $h=0; + for($j=0; $j < $n; ++$j) { + $h = max($h,$this->iCells[$i][$j]->GetHeight($aImg)); + } + if( isset($this->iRowHeight[$i]) ) { + $this->iRowHeight[$i] = max($h,$this->iRowHeight[$i]); + } + else + $this->iRowHeight[$i] = $h; + } + + // Get maximum col width per columns + for($j=0; $j < $n; ++$j) { + $w=0; + for($i=0; $i < $m; ++$i) { + $w = max($w,$this->iCells[$i][$j]->GetWidth($aImg)); + } + if( isset($this->iColWidth[$j]) ) { + $this->iColWidth[$j] = max($w,$this->iColWidth[$j]); + } + else + $this->iColWidth[$j] = $w; + } + } + + function _setcell($aRow,$aCol,$aVal='') { + if( isset($this->iCells[$aRow][$aCol]) ) { + $this->iCells[$aRow][$aCol]->Set($aVal); + } + else { + $this->iCells[$aRow][$aCol] = new GTextTableCell((string)$aVal,$aRow,$aCol); + $this->iCells[$aRow][$aCol]->Init($this); + } + } + + function StrokeWithScale($aImg,$aXScale,$aYScale) { + if( is_numeric($this->iScaleXPos) && is_numeric($this->iScaleYPos) ) { + $x = round($aXScale->Translate($this->iScaleXPos)); + $y = round($aYScale->Translate($this->iScaleYPos)); + $this->Stroke($aImg,$x,$y); + } + else { + $this->Stroke($aImg); + } + } + + function Stroke($aImg,$aX=NULL,$aY=NULL) { + if( $aX !== NULL && $aY !== NULL ) { + $this->iXPos = $aX; + $this->iYPos = $aY; + } + + $rc = $this->iSize[0]; // row count + $cc = $this->iSize[1]; // column count + + if( $rc == 0 || $cc == 0 ) { + JpGraphError::RaiseL(27009); + } + + // Adjust margins of each cell based on the weight of the grid. Each table grid line + // is actually occupying the left side and top part of each cell. + for($j=0; $j < $cc; ++$j) { + $this->iCells[0][$j]->iMarginTop += $this->iBorderWeight; + } + for($i=0; $i < $rc; ++$i) { + $this->iCells[$i][0]->iMarginLeft += $this->iBorderWeight; + } + for($i=0; $i < $rc; ++$i) { + for($j=0; $j < $cc; ++$j) { + $this->iCells[$i][$j]->AdjustMarginsForGrid(); + } + } + + // adjust row and column size depending on cell content + $this->_autoSizeTable($aImg); + + if( $this->iSize[1] != count($this->iColWidth) || $this->iSize[0] != count($this->iRowHeight) ) { + JpGraphError::RaiseL(27008); + //('Column and row size arrays must match the dimesnions of the table'); + } + + // Find out overall table size + $width=0; + for($i=0; $i < $cc; ++$i) { + $width += $this->iColWidth[$i]; + } + $height=0; + for($i=0; $i < $rc; ++$i) { + $height += $this->iRowHeight[$i]; + } + + // Adjust the X,Y position to alway be at the top left corner + // The anchor position, i.e. how the client want to interpret the specified + // x and y coordinate must be taken into account + switch( strtolower($this->iXAnchor) ) { + case 'left' : + break; + case 'center': + $this->iXPos -= round($width/2); + break; + case 'right': + $this->iXPos -= $width; + break; + } + switch( strtolower($this->iYAnchor) ) { + case 'top' : + break; + case 'center': + case 'middle': + $this->iYPos -= round($height/2); + break; + case 'bottom': + $this->iYPos -= $height; + break; + } + + // Set the overall background color of the table if set + if( $this->iBGColor !== '' ) { + $aImg->SetColor($this->iBGColor); + $aImg->FilledRectangle($this->iXPos,$this->iYPos,$this->iXPos+$width,$this->iYPos+$height); + } + + // Stroke all cells + $rpos=$this->iYPos; + for($i=0; $i < $rc; ++$i) { + $cpos=$this->iXPos; + for($j=0; $j < $cc; ++$j) { + // Calculate width and height of this cell if it is spanning + // more than one column or row + $cwidth=0; + for( $k=0; $k < $this->iCells[$i][$j]->iColSpan; ++$k ) { + $cwidth += $this->iColWidth[$j+$k]; + } + $cheight=0; + for( $k=0; $k < $this->iCells[$i][$j]->iRowSpan; ++$k ) { + $cheight += $this->iRowHeight[$i+$k]; + } + + $this->iCells[$i][$j]->Stroke($aImg,$cpos,$rpos,$cwidth,$cheight); + $cpos += $this->iColWidth[$j]; + } + $rpos += $this->iRowHeight[$i]; + } + + // Stroke outer border + $aImg->SetColor($this->iBorderColor); + if( $this->iBorderWeight == 1 ) + $aImg->Rectangle($this->iXPos,$this->iYPos,$this->iXPos+$width,$this->iYPos+$height); + else { + for( $i=0; $i < $this->iBorderWeight; ++$i ) + $aImg->Rectangle($this->iXPos+$i,$this->iYPos+$i, + $this->iXPos+$width-1+$this->iBorderWeight-$i, + $this->iYPos+$height-1+$this->iBorderWeight-$i); + } + } +} + +/* + EOF + */ +?> diff --git a/src/classes/jpgraph/jpgraph_text.inc.php b/src/classes/jpgraph/jpgraph_text.inc.php index c93846b..7d0f668 100644 --- a/src/classes/jpgraph/jpgraph_text.inc.php +++ b/src/classes/jpgraph/jpgraph_text.inc.php @@ -6,7 +6,7 @@ // Created: 2001-01-08 (Refactored to separate file 2008-08-01) // Ver: $Id: jpgraph_text.inc.php 1844 2009-09-26 17:05:31Z ljp $ // -// Copyright (c) Aditus Consulting. All rights reserved. +// Copyright (c) Asial Corporation. All rights reserved. //======================================================================== @@ -15,12 +15,12 @@ // Description: Arbitrary text object that can be added to the graph //=================================================== class Text { - public $t,$margin=0; + public $t; public $x=0,$y=0,$halign="left",$valign="top",$color=array(0,0,0); public $hide=false, $dir=0; public $iScalePosY=null,$iScalePosX=null; public $iWordwrap=0; - public $font_family=FF_FONT1,$font_style=FS_NORMAL,$font_size=12; + public $font_family=FF_DEFAULT,$font_style=FS_NORMAL; // old. FF_FONT1 protected $boxed=false; // Should the text be boxed protected $paragraph_align="left"; protected $icornerradius=0,$ishadowwidth=3; @@ -28,6 +28,10 @@ class Text { protected $iCSIMarea='',$iCSIMalt='',$iCSIMtarget='',$iCSIMWinTarget=''; private $iBoxType = 1; // Which variant of filled box around text we want + // for __get, __set + private $_margin; + private $_font_size=8; // old. 12 + //--------------- // CONSTRUCTOR @@ -171,28 +175,28 @@ class Text { // Total width of text function GetWidth($aImg) { - $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $aImg->SetFont($this->font_family,$this->font_style,$this->raw_font_size); $w = $aImg->GetTextWidth($this->t,$this->dir); return $w; } // Hight of font function GetFontHeight($aImg) { - $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $aImg->SetFont($this->font_family,$this->font_style,$this->raw_font_size); $h = $aImg->GetFontHeight(); return $h; } function GetTextHeight($aImg) { - $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $aImg->SetFont($this->font_family,$this->font_style,$this->raw_font_size); $h = $aImg->GetTextHeight($this->t,$this->dir); return $h; } function GetHeight($aImg) { // Synonym for GetTextHeight() - $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $aImg->SetFont($this->font_family,$this->font_style,$this->raw_font_size); $h = $aImg->GetTextHeight($this->t,$this->dir); return $h; } @@ -246,7 +250,7 @@ class Text { if( $this->y < 1 && $this->y > 0 ) $this->y *= $aImg->height; $aImg->PushColor($this->color); - $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $aImg->SetFont($this->font_family,$this->font_style,$this->raw_font_size); $aImg->SetTextAlign($this->halign,$this->valign); if( $this->boxed ) { @@ -296,6 +300,27 @@ class Text { $aImg->PopColor($this->color); } + + function __get($name) { + + if (strpos($name, 'raw_') !== false) { + // if $name == 'raw_left_margin' , return $this->_left_margin; + $variable_name = '_' . str_replace('raw_', '', $name); + return $this->$variable_name; + } + + $variable_name = '_' . $name; + + if (isset($this->$variable_name)) { + return $this->$variable_name * SUPERSAMPLING_SCALE; + } else { + JpGraphError::RaiseL('25132', $name); + } + } + + function __set($name, $value) { + $this->{'_'.$name} = $value; + } } // Class diff --git a/src/classes/jpgraph/jpgraph_theme.inc.php b/src/classes/jpgraph/jpgraph_theme.inc.php new file mode 100644 index 0000000..0cc54c4 --- /dev/null +++ b/src/classes/jpgraph/jpgraph_theme.inc.php @@ -0,0 +1,136 @@ +color_index = 0; + } + /** + * + */ + abstract function GetColorList(); + + /** + * + */ + abstract function ApplyPlot($plot); + + + /** + * + */ + function SetupPlot($plot) { + if (is_array($plot)) { + foreach ($plot as $obj) { + $this->ApplyPlot($obj); + } + } else { + $this->ApplyPlot($plot); + } + } + + /** + * + */ + function ApplyGraph($graph) { + + $this->graph = $graph; + $method_name = ''; + + if (get_class($graph) == 'Graph') { + $method_name = 'SetupGraph'; + } else { + $method_name = 'Setup' . get_class($graph); + } + + if (method_exists($this, $method_name)) { + $this->$method_name($graph); + } else { + JpGraphError::RaiseL(30001, $method_name, $method_name); //Theme::%s() is not defined. \nPlease make %s(\$graph) function in your theme classs. + } + } + + /** + * + */ + function PreStrokeApply($graph) { + } + + /** + * + */ + function GetThemeColors($num = 30) { + $result_list = array(); + + $old_index = $this->color_index; + $this->color_index = 0; + $count = 0; + + $i = 0; + while (true) { + for ($j = 0; $j < count($this->GetColorList()); $j++) { + if (++$count > $num) { + break 2; + } + $result_list[] = $this->GetNextColor(); + } + $i++; + } + + $this->color_index = $old_index; + + return $result_list; + } + + /** + * + */ + function GetNextColor() { + $color_list = $this->GetColorList(); + + $color = null; + if (isset($color_list[$this->color_index])) { + $color = $color_list[$this->color_index]; + } else { + $color_count = count($color_list); + if ($color_count <= $this->color_index) { + $color_tmp = $color_list[$this->color_index % $color_count]; + $brightness = 1.0 - intval($this->color_index / $color_count) * 0.2; + $rgb = new RGB(); + $color = $color_tmp . ':' . $brightness; + $color = $rgb->Color($color); + $alpha = array_pop($color); + $color = $rgb->tryHexConversion($color); + if ($alpha) { + $color .= '@' . $alpha; + } + } + } + + $this->color_index++; + + return $color; + } + +} // Class + +?> diff --git a/src/classes/jpgraph/jpgraph_ttf.inc.php b/src/classes/jpgraph/jpgraph_ttf.inc.php index 1e0d524..5a1bc3e 100644 --- a/src/classes/jpgraph/jpgraph_ttf.inc.php +++ b/src/classes/jpgraph/jpgraph_ttf.inc.php @@ -5,7 +5,7 @@ // Created: 2006-11-19 // Ver: $Id: jpgraph_ttf.inc.php 1858 2009-09-28 14:39:51Z ljp $ // -// Copyright (c) Aditus Consulting. All rights reserved. +// Copyright (c) Asial Corporation. All rights reserved. //======================================================================== // TTF Font families @@ -144,6 +144,11 @@ define('PGOTHIC_TTF_FONT','ipagp.ttf'); define('ASSUME_EUCJP_ENCODING',false); +// Default font family +define('FF_DEFAULT', FF_DV_SANSSERIF); + + + //================================================================= // CLASS LanguageConv // Description: @@ -467,37 +472,46 @@ class TTF { } $ff = @$fam[$style]; - if( is_array($ff) ) { - // There are several optional file names. They are tried in order - // and the first one found is used - $n = count($ff); - } else { - $n = 1; + // There are several optional file names. They are tried in order + // and the first one found is used + if( !is_array($ff) ) { $ff = array($ff); } - $i = 0; - do { - $f = $ff[$i]; + + $jpgraph_font_dir = dirname(__FILE__).'/fonts/'; + + foreach ($ff as $font_file) { // All font families are guaranteed to have the normal style - if( $f==='' ) + if( $font_file==='' ) JpGraphError::RaiseL(25047,$this->style_names[$style],$this->font_files[$family][FS_NORMAL]);//('Style "'.$this->style_names[$style].'" is not available for font family '.$this->font_files[$family][FS_NORMAL].'.'); - if( !$f ) { + if( !$font_file ) { JpGraphError::RaiseL(25048,$fam);//("Unknown font style specification [$fam]."); } - if ($family >= FF_MINCHO && $family <= FF_PGOTHIC) { - $f = MBTTF_DIR.$f; - } else { - $f = TTF_DIR.$f; + // check jpgraph/src/fonts dir + $jpgraph_font_file = $jpgraph_font_dir . $font_file; + if (file_exists($jpgraph_font_file) === true && is_readable($jpgraph_font_file) === true) { + $font_file = $jpgraph_font_file; + break; } - ++$i; - } while( $i < $n && (file_exists($f) === false || is_readable($f) === false) ); - if( !file_exists($f) ) { - JpGraphError::RaiseL(25049,$f);//("Font file \"$f\" is not readable or does not exist."); + // check OS font dir + if ($family >= FF_MINCHO && $family <= FF_PGOTHIC) { + $font_file = MBTTF_DIR.$font_file; + } else { + $font_file = TTF_DIR.$font_file; + } + if (file_exists($font_file) === true && is_readable($font_file) === true) { + break; + } } - return $f; + + if( !file_exists($font_file) ) { + JpGraphError::RaiseL(25049,$font_file);//("Font file \"$font_file\" is not readable or does not exist."); + } + + return $font_file; } function SetUserFont($aNormal,$aBold='',$aItalic='',$aBoldIt='') { diff --git a/src/classes/jpgraph/jpgraph_utils.inc.php b/src/classes/jpgraph/jpgraph_utils.inc.php new file mode 100644 index 0000000..f0d002c --- /dev/null +++ b/src/classes/jpgraph/jpgraph_utils.inc.php @@ -0,0 +1,685 @@ +iFunc = $aFunc; + $this->iXFunc = $aXFunc; + } + + function E($aXMin,$aXMax,$aSteps=50) { + $this->iMin = $aXMin; + $this->iMax = $aXMax; + $this->iStepSize = ($aXMax-$aXMin)/$aSteps; + + if( $this->iXFunc != '' ) + $t = 'for($i='.$aXMin.'; $i<='.$aXMax.'; $i += '.$this->iStepSize.') {$ya[]='.$this->iFunc.';$xa[]='.$this->iXFunc.';}'; + elseif( $this->iFunc != '' ) + $t = 'for($x='.$aXMin.'; $x<='.$aXMax.'; $x += '.$this->iStepSize.') {$ya[]='.$this->iFunc.';$xa[]=$x;} $x='.$aXMax.';$ya[]='.$this->iFunc.';$xa[]=$x;'; + else + JpGraphError::RaiseL(24001);//('FuncGenerator : No function specified. '); + + @eval($t); + + // If there is an error in the function specifcation this is the only + // way we can discover that. + if( empty($xa) || empty($ya) ) + JpGraphError::RaiseL(24002);//('FuncGenerator : Syntax error in function specification '); + + return array($xa,$ya); + } +} + + +//============================================================================= +// CLASS DateScaleUtils +// Description: Help to create a manual date scale +//============================================================================= +define('DSUTILS_MONTH',1); // Major and minor ticks on a monthly basis +define('DSUTILS_MONTH1',1); // Major and minor ticks on a monthly basis +define('DSUTILS_MONTH2',2); // Major ticks on a bi-monthly basis +define('DSUTILS_MONTH3',3); // Major icks on a tri-monthly basis +define('DSUTILS_MONTH6',4); // Major on a six-monthly basis +define('DSUTILS_WEEK1',5); // Major ticks on a weekly basis +define('DSUTILS_WEEK2',6); // Major ticks on a bi-weekly basis +define('DSUTILS_WEEK4',7); // Major ticks on a quod-weekly basis +define('DSUTILS_DAY1',8); // Major ticks on a daily basis +define('DSUTILS_DAY2',9); // Major ticks on a bi-daily basis +define('DSUTILS_DAY4',10); // Major ticks on a qoud-daily basis +define('DSUTILS_YEAR1',11); // Major ticks on a yearly basis +define('DSUTILS_YEAR2',12); // Major ticks on a bi-yearly basis +define('DSUTILS_YEAR5',13); // Major ticks on a five-yearly basis + + +class DateScaleUtils { + public static $iMin=0, $iMax=0; + + private static $starthour,$startmonth, $startday, $startyear; + private static $endmonth, $endyear, $endday; + private static $tickPositions=array(),$minTickPositions=array(); + private static $iUseWeeks = true; + + static function UseWeekFormat($aFlg) { + self::$iUseWeeks = $aFlg; + } + + static function doYearly($aType,$aMinor=false) { + $i=0; $j=0; + $m = self::$startmonth; + $y = self::$startyear; + + if( self::$startday == 1 ) { + self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); + } + ++$m; + + + switch( $aType ) { + case DSUTILS_YEAR1: + for($y=self::$startyear; $y <= self::$endyear; ++$y ) { + if( $aMinor ) { + while( $m <= 12 ) { + if( !($y == self::$endyear && $m > self::$endmonth) ) { + self::$minTickPositions[$j++] = mktime(0,0,0,$m,1,$y); + } + ++$m; + } + $m=1; + } + self::$tickPositions[$i++] = mktime(0,0,0,1,1,$y); + } + break; + case DSUTILS_YEAR2: + $y=self::$startyear; + while( $y <= self::$endyear ) { + self::$tickPositions[$i++] = mktime(0,0,0,1,1,$y); + for($k=0; $k < 1; ++$k ) { + ++$y; + if( $aMinor ) { + self::$minTickPositions[$j++] = mktime(0,0,0,1,1,$y); + } + } + ++$y; + } + break; + case DSUTILS_YEAR5: + $y=self::$startyear; + while( $y <= self::$endyear ) { + self::$tickPositions[$i++] = mktime(0,0,0,1,1,$y); + for($k=0; $k < 4; ++$k ) { + ++$y; + if( $aMinor ) { + self::$minTickPositions[$j++] = mktime(0,0,0,1,1,$y); + } + } + ++$y; + } + break; + } + } + + static function doDaily($aType,$aMinor=false) { + $m = self::$startmonth; + $y = self::$startyear; + $d = self::$startday; + $h = self::$starthour; + $i=0;$j=0; + + if( $h == 0 ) { + self::$tickPositions[$i++] = mktime(0,0,0,$m,$d,$y); + } + $t = mktime(0,0,0,$m,$d,$y); + + switch($aType) { + case DSUTILS_DAY1: + while( $t <= self::$iMax ) { + $t = strtotime('+1 day',$t); + self::$tickPositions[$i++] = $t; + if( $aMinor ) { + self::$minTickPositions[$j++] = strtotime('+12 hours',$t); + } + } + break; + case DSUTILS_DAY2: + while( $t <= self::$iMax ) { + $t = strtotime('+1 day',$t); + if( $aMinor ) { + self::$minTickPositions[$j++] = $t; + } + $t = strtotime('+1 day',$t); + self::$tickPositions[$i++] = $t; + } + break; + case DSUTILS_DAY4: + while( $t <= self::$iMax ) { + for($k=0; $k < 3; ++$k ) { + $t = strtotime('+1 day',$t); + if( $aMinor ) { + self::$minTickPositions[$j++] = $t; + } + } + $t = strtotime('+1 day',$t); + self::$tickPositions[$i++] = $t; + } + break; + } + } + + static function doWeekly($aType,$aMinor=false) { + $hpd = 3600*24; + $hpw = 3600*24*7; + // Find out week number of min date + $thursday = self::$iMin + $hpd * (3 - (date('w', self::$iMin) + 6) % 7); + $week = 1 + (date('z', $thursday) - (11 - date('w', mktime(0, 0, 0, 1, 1, date('Y', $thursday)))) % 7) / 7; + $daynumber = date('w',self::$iMin); + if( $daynumber == 0 ) $daynumber = 7; + $m = self::$startmonth; + $y = self::$startyear; + $d = self::$startday; + $i=0;$j=0; + // The assumption is that the weeks start on Monday. If the first day + // is later in the week then the first week tick has to be on the following + // week. + if( $daynumber == 1 ) { + self::$tickPositions[$i++] = mktime(0,0,0,$m,$d,$y); + $t = mktime(0,0,0,$m,$d,$y) + $hpw; + } + else { + $t = mktime(0,0,0,$m,$d,$y) + $hpd*(8-$daynumber); + } + + switch($aType) { + case DSUTILS_WEEK1: + $cnt=0; + break; + case DSUTILS_WEEK2: + $cnt=1; + break; + case DSUTILS_WEEK4: + $cnt=3; + break; + } + while( $t <= self::$iMax ) { + self::$tickPositions[$i++] = $t; + for($k=0; $k < $cnt; ++$k ) { + $t += $hpw; + if( $aMinor ) { + self::$minTickPositions[$j++] = $t; + } + } + $t += $hpw; + } + } + + static function doMonthly($aType,$aMinor=false) { + $monthcount=0; + $m = self::$startmonth; + $y = self::$startyear; + $i=0; $j=0; + + // Skip the first month label if it is before the startdate + if( self::$startday == 1 ) { + self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); + $monthcount=1; + } + if( $aType == 1 ) { + if( self::$startday < 15 ) { + self::$minTickPositions[$j++] = mktime(0,0,0,$m,15,$y); + } + } + ++$m; + + // Loop through all the years included in the scale + for($y=self::$startyear; $y <= self::$endyear; ++$y ) { + // Loop through all the months. There are three cases to consider: + // 1. We are in the first year and must start with the startmonth + // 2. We are in the end year and we must stop at last month of the scale + // 3. A year in between where we run through all the 12 months + $stopmonth = $y == self::$endyear ? self::$endmonth : 12; + while( $m <= $stopmonth ) { + switch( $aType ) { + case DSUTILS_MONTH1: + // Set minor tick at the middle of the month + if( $aMinor ) { + if( $m <= $stopmonth ) { + if( !($y==self::$endyear && $m==$stopmonth && self::$endday < 15) ) + self::$minTickPositions[$j++] = mktime(0,0,0,$m,15,$y); + } + } + // Major at month + // Get timestamp of first hour of first day in each month + self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); + + break; + case DSUTILS_MONTH2: + if( $aMinor ) { + // Set minor tick at start of each month + self::$minTickPositions[$j++] = mktime(0,0,0,$m,1,$y); + } + + // Major at every second month + // Get timestamp of first hour of first day in each month + if( $monthcount % 2 == 0 ) { + self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); + } + break; + case DSUTILS_MONTH3: + if( $aMinor ) { + // Set minor tick at start of each month + self::$minTickPositions[$j++] = mktime(0,0,0,$m,1,$y); + } + // Major at every third month + // Get timestamp of first hour of first day in each month + if( $monthcount % 3 == 0 ) { + self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); + } + break; + case DSUTILS_MONTH6: + if( $aMinor ) { + // Set minor tick at start of each month + self::$minTickPositions[$j++] = mktime(0,0,0,$m,1,$y); + } + // Major at every third month + // Get timestamp of first hour of first day in each month + if( $monthcount % 6 == 0 ) { + self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); + } + break; + } + ++$m; + ++$monthcount; + } + $m=1; + } + + // For the case where all dates are within the same month + // we want to make sure we have at least two ticks on the scale + // since the scale want work properly otherwise + if(self::$startmonth == self::$endmonth && self::$startyear == self::$endyear && $aType==1 ) { + self::$tickPositions[$i++] = mktime(0 ,0 ,0, self::$startmonth + 1, 1, self::$startyear); + } + + return array(self::$tickPositions,self::$minTickPositions); + } + + static function GetTicks($aData,$aType=1,$aMinor=false,$aEndPoints=false) { + $n = count($aData); + return self::GetTicksFromMinMax($aData[0],$aData[$n-1],$aType,$aMinor,$aEndPoints); + } + + static function GetAutoTicks($aMin,$aMax,$aMaxTicks=10,$aMinor=false) { + $diff = $aMax - $aMin; + $spd = 3600*24; + $spw = $spd*7; + $spm = $spd*30; + $spy = $spd*352; + + if( self::$iUseWeeks ) + $w = 'W'; + else + $w = 'd M'; + + // Decision table for suitable scales + // First value: Main decision point + // Second value: Array of formatting depending on divisor for wanted max number of ticks. ,.. + $tt = array( + array($spw, array(1,DSUTILS_DAY1,'d M',2,DSUTILS_DAY2,'d M',-1,DSUTILS_DAY4,'d M')), + array($spm, array(1,DSUTILS_DAY1,'d M',2,DSUTILS_DAY2,'d M',4,DSUTILS_DAY4,'d M',7,DSUTILS_WEEK1,$w,-1,DSUTILS_WEEK2,$w)), + array($spy, array(1,DSUTILS_DAY1,'d M',2,DSUTILS_DAY2,'d M',4,DSUTILS_DAY4,'d M',7,DSUTILS_WEEK1,$w,14,DSUTILS_WEEK2,$w,30,DSUTILS_MONTH1,'M',60,DSUTILS_MONTH2,'M',-1,DSUTILS_MONTH3,'M')), + array(-1, array(30,DSUTILS_MONTH1,'M-Y',60,DSUTILS_MONTH2,'M-Y',90,DSUTILS_MONTH3,'M-Y',180,DSUTILS_MONTH6,'M-Y',352,DSUTILS_YEAR1,'Y',704,DSUTILS_YEAR2,'Y',-1,DSUTILS_YEAR5,'Y'))); + + $ntt = count($tt); + $nd = floor($diff/$spd); + for($i=0; $i < $ntt; ++$i ) { + if( $diff <= $tt[$i][0] || $i==$ntt-1) { + $t = $tt[$i][1]; + $n = count($t)/3; + for( $j=0; $j < $n; ++$j ) { + if( $nd/$t[3*$j] <= $aMaxTicks || $j==$n-1) { + $type = $t[3*$j+1]; + $fs = $t[3*$j+2]; + list($tickPositions,$minTickPositions) = self::GetTicksFromMinMax($aMin,$aMax,$type,$aMinor); + return array($fs,$tickPositions,$minTickPositions,$type); + } + } + } + } + } + + static function GetTicksFromMinMax($aMin,$aMax,$aType,$aMinor=false,$aEndPoints=false) { + self::$starthour = date('G',$aMin); + self::$startmonth = date('n',$aMin); + self::$startday = date('j',$aMin); + self::$startyear = date('Y',$aMin); + self::$endmonth = date('n',$aMax); + self::$endyear = date('Y',$aMax); + self::$endday = date('j',$aMax); + self::$iMin = $aMin; + self::$iMax = $aMax; + + if( $aType <= DSUTILS_MONTH6 ) { + self::doMonthly($aType,$aMinor); + } + elseif( $aType <= DSUTILS_WEEK4 ) { + self::doWeekly($aType,$aMinor); + } + elseif( $aType <= DSUTILS_DAY4 ) { + self::doDaily($aType,$aMinor); + } + elseif( $aType <= DSUTILS_YEAR5 ) { + self::doYearly($aType,$aMinor); + } + else { + JpGraphError::RaiseL(24003); + } + // put a label at the very left data pos + if( $aEndPoints ) { + $tickPositions[$i++] = $aData[0]; + } + + // put a label at the very right data pos + if( $aEndPoints ) { + $tickPositions[$i] = $aData[$n-1]; + } + + return array(self::$tickPositions,self::$minTickPositions); + } +} + +//============================================================================= +// Class ReadFileData +//============================================================================= +Class ReadFileData { + //---------------------------------------------------------------------------- + // Desciption: + // Read numeric data from a file. + // Each value should be separated by either a new line or by a specified + // separator character (default is ','). + // Before returning the data each value is converted to a proper float + // value. The routine is robust in the sense that non numeric data in the + // file will be discarded. + // + // Returns: + // The number of data values read on success, FALSE on failure + //---------------------------------------------------------------------------- + static function FromCSV($aFile,&$aData,$aSepChar=',',$aMaxLineLength=1024) { + $rh = @fopen($aFile,'r'); + if( $rh === false ) { + return false; + } + $tmp = array(); + $lineofdata = fgetcsv($rh, 1000, ','); + while ( $lineofdata !== FALSE) { + $tmp = array_merge($tmp,$lineofdata); + $lineofdata = fgetcsv($rh, $aMaxLineLength, $aSepChar); + } + fclose($rh); + + // Now make sure that all data is numeric. By default + // all data is read as strings + $n = count($tmp); + $aData = array(); + $cnt=0; + for($i=0; $i < $n; ++$i) { + if( $tmp[$i] !== "" ) { + $aData[$cnt++] = floatval($tmp[$i]); + } + } + return $cnt; + } + + //---------------------------------------------------------------------------- + // Desciption: + // Read numeric data from a file. + // Each value should be separated by either a new line or by a specified + // separator character (default is ','). + // Before returning the data each value is converted to a proper float + // value. The routine is robust in the sense that non numeric data in the + // file will be discarded. + // + // Options: + // 'separator' => ',', + // 'enclosure' => '"', + // 'readlength' => 1024, + // 'ignore_first' => false, + // 'first_as_key' => false + // 'escape' => '\', # PHP >= 5.3 only + // + // Returns: + // The number of lines read on success, FALSE on failure + //---------------------------------------------------------------------------- + static function FromCSV2($aFile, &$aData, $aOptions = array()) { + $aDefaults = array( + 'separator' => ',', + 'enclosure' => chr(34), + 'escape' => chr(92), + 'readlength' => 1024, + 'ignore_first' => false, + 'first_as_key' => false + ); + + $aOptions = array_merge( + $aDefaults, is_array($aOptions) ? $aOptions : array()); + + if( $aOptions['first_as_key'] ) { + $aOptions['ignore_first'] = true; + } + + $rh = @fopen($aFile, 'r'); + + if( $rh === false ) { + return false; + } + + $aData = array(); + $aLine = fgetcsv($rh, + $aOptions['readlength'], + $aOptions['separator'], + $aOptions['enclosure'] + /*, $aOptions['escape'] # PHP >= 5.3 only */ + ); + + // Use numeric array keys for the columns by default + // If specified use first lines values as assoc keys instead + $keys = array_keys($aLine); + if( $aOptions['first_as_key'] ) { + $keys = array_values($aLine); + } + + $num_lines = 0; + $num_cols = count($aLine); + + while ($aLine !== false) { + if( is_array($aLine) && count($aLine) != $num_cols ) { + JpGraphError::RaiseL(24004); + // 'ReadCSV2: Column count mismatch in %s line %d' + } + + // fgetcsv returns NULL for empty lines + if( !is_null($aLine) ) { + $num_lines++; + + if( !($aOptions['ignore_first'] && $num_lines == 1) && is_numeric($aLine[0]) ) { + for( $i = 0; $i < $num_cols; $i++ ) { + $aData[ $keys[$i] ][] = floatval($aLine[$i]); + } + } + } + + $aLine = fgetcsv($rh, + $aOptions['readlength'], + $aOptions['separator'], + $aOptions['enclosure'] + /*, $aOptions['escape'] # PHP >= 5.3 only*/ + ); + } + + fclose($rh); + + if( $aOptions['ignore_first'] ) { + $num_lines--; + } + + return $num_lines; + } + + // Read data from two columns in a plain text file + static function From2Col($aFile, $aCol1, $aCol2, $aSepChar=' ') { + $lines = @file($aFile,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); + if( $lines === false ) { + return false; + } + $s = '/[\s]+/'; + if( $aSepChar == ',' ) { + $s = '/[\s]*,[\s]*/'; + } + elseif( $aSepChar == ';' ) { + $s = '/[\s]*;[\s]*/'; + } + foreach( $lines as $line => $datarow ) { + $split = preg_split($s,$datarow); + $aCol1[] = floatval(trim($split[0])); + $aCol2[] = floatval(trim($split[1])); + } + + return count($lines); + } + + // Read data from one columns in a plain text file + static function From1Col($aFile, $aCol1) { + $lines = @file($aFile,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); + if( $lines === false ) { + return false; + } + foreach( $lines as $line => $datarow ) { + $aCol1[] = floatval(trim($datarow)); + } + + return count($lines); + } + + static function FromMatrix($aFile,$aSepChar=' ') { + $lines = @file($aFile,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); + if( $lines === false ) { + return false; + } + $mat = array(); + $reg = '/'.$aSepChar.'/'; + foreach( $lines as $line => $datarow ) { + $row = preg_split($reg,trim($datarow)); + foreach ($row as $key => $cell ) { + $row[$key] = floatval(trim($cell)); + } + $mat[] = $row; + } + return $mat; + } + + +} + +define('__LR_EPSILON', 1.0e-8); +//============================================================================= +// Class LinearRegression +//============================================================================= +class LinearRegression { + private $ix=array(),$iy=array(); + private $ib=0, $ia=0; + private $icalculated=false; + public $iDet=0, $iCorr=0, $iStdErr=0; + + public function __construct($aDataX,$aDataY) { + if( count($aDataX) !== count($aDataY) ) { + JpGraph::Raise('LinearRegression: X and Y data array must be of equal length.'); + } + $this->ix = $aDataX; + $this->iy = $aDataY; + } + + public function Calc() { + + $this->icalculated = true; + + $n = count($this->ix); + $sx2 = 0 ; + $sy2 = 0 ; + $sxy = 0 ; + $sx = 0 ; + $sy = 0 ; + + for( $i=0; $i < $n; ++$i ) { + $sx2 += $this->ix[$i] * $this->ix[$i]; + $sy2 += $this->iy[$i] * $this->iy[$i]; + $sxy += $this->ix[$i] * $this->iy[$i]; + $sx += $this->ix[$i]; + $sy += $this->iy[$i]; + } + + if( $n*$sx2 - $sx*$sx > __LR_EPSILON ) { + $this->ib = ($n*$sxy - $sx*$sy) / ( $n*$sx2 - $sx*$sx ); + $this->ia = ( $sy - $this->ib*$sx ) / $n; + + $sx = $this->ib * ( $sxy - $sx*$sy/$n ); + $sy2 = $sy2 - $sy*$sy/$n; + $sy = $sy2 - $sx; + + $this->iDet = $sx / $sy2; + $this->iCorr = sqrt($this->iDet); + if( $n > 2 ) { + $this->iStdErr = sqrt( $sy / ($n-2) ); + } + else { + $this->iStdErr = NAN ; + } + } + else { + $this->ib = 0; + $this->ia = 0; + } + + } + + public function GetAB() { + if( $this->icalculated == false ) + $this->Calc(); + return array($this->ia, $this->ib); + } + + public function GetStat() { + if( $this->icalculated == false ) + $this->Calc(); + return array($this->iStdErr, $this->iCorr, $this->iDet); + } + + public function GetY($aMinX, $aMaxX, $aStep=1) { + if( $this->icalculated == false ) + $this->Calc(); + + $yy = array(); + $i = 0; + for( $x=$aMinX; $x <= $aMaxX; $x += $aStep ) { + $xx[$i ] = $x; + $yy[$i++] = $this->ia + $this->ib * $x; + } + + return array($xx,$yy); + } + +} + +?> diff --git a/src/classes/jpgraph/jpgraph_windrose.php b/src/classes/jpgraph/jpgraph_windrose.php new file mode 100644 index 0000000..8eef2cb --- /dev/null +++ b/src/classes/jpgraph/jpgraph_windrose.php @@ -0,0 +1,1566 @@ +iZeroSum=0; + foreach( $aData as $idx => $legdata ) { + $legsum = array_sum($legdata); + $maxnum = max($maxnum,count($legdata)-1); + $max = max($legsum-$legdata[0],$max); + $totlegsum += $legsum; + $this->iZeroSum += $legdata[0] ; + } + if( round($totlegsum) > 100 ) { + JpGraphError::RaiseL(22001,$legsum); + //("Total percentage for all windrose legs in a windrose plot can not exceed 100% !\n(Current max is: ".$legsum.')'); + } + $this->iMax = $max ; + $this->iMaxNum = $maxnum; + $this->iNumCirc = $this->GetNumCirc(); + $this->iMaxVal = $this->iNumCirc * $this->iDelta ; + } + + // Return number of grid circles + function GetNumCirc() { + // Never return less than 1 circles + $num = ceil($this->iMax / $this->iDelta); + return max(1,$num) ; + } + + function SetMaxValue($aMax) { + $this->iMax = $aMax; + $this->iNumCirc = $this->GetNumCirc(); + $this->iMaxVal = $this->iNumCirc * $this->iDelta ; + } + + // Set step size for circular grid + function Set($aMax,$aDelta=null) { + if( $aDelta==null ) { + $this->SetMaxValue($aMax); + return; + } + $this->iDelta = $aDelta; + $this->iNumCirc = ceil($aMax/$aDelta); //$this->GetNumCirc(); + $this->iMaxVal = $this->iNumCirc * $this->iDelta ; + $this->iMax=$aMax; + // Remember that user has specified interval so don't + // do autoscaling + $this->iManualScale = true; + } + + function AutoScale($aRadius,$aMinDist=30) { + + if( $this->iManualScale ) return; + + // Make sure distance (in pixels) between two circles + // is never less than $aMinDist pixels + $tst = ceil($aRadius / $this->iNumCirc) ; + + while( $tst <= $aMinDist && $this->iDelta < 100 ) { + $this->iDelta += 5; + $tst = ceil($aRadius / $this->GetNumCirc()) ; + } + + if( $this->iDelta >= 100 ) { + JpGraphError::RaiseL(22002);//('Graph is too small to have a scale. Please make the graph larger.'); + } + + // If the distance is to large try with multiples of 2 instead + if( $tst > $aMinDist * 3 ) { + $this->iDelta = 2; + $tst = ceil($aRadius / $this->iNumCirc) ; + + while( $tst <= $aMinDist && $this->iDelta < 100 ) { + $this->iDelta += 2; + $tst = ceil($aRadius / $this->GetNumCirc()) ; + } + + if( $this->iDelta >= 100 ) { + JpGraphError::RaiseL(22002); //('Graph is too small to have a scale. Please make the graph larger.'); + } + } + + $this->iNumCirc = $this->GetNumCirc(); + $this->iMaxVal = $this->iNumCirc * $this->iDelta ; + } + + // Return max of all leg values + function GetMax() { + return $this->iMax; + } + + function Hide($aFlg=true) { + $this->iHideLabels = $aFlg; + } + + function SetAngle($aAngle) { + $this->iAngle = $aAngle ; + } + + // Translate a Leg value to radius distance + function RelTranslate($aVal,$r,$ri) { + $tv = round($aVal/$this->iMaxVal*($r-$ri)); + return $tv ; + } + + function SetLabelAlign($aAlign) { + $this->iLblAlign = $aAlign ; + } + + function SetLabelFormat($aFmt) { + $this->iLblFmt = $aFmt ; + } + + function SetLabelFillColor($aBkgColor,$aBorderColor=false) { + + $this->iFontBkgColor = $aBkgColor; + if( $aBorderColor === false ) { + $this->iFontFrameColor = $aBkgColor; + } + else { + $this->iFontFrameColor = $aBorderColor; + } + } + + function SetFontColor($aColor) { + $this->iFontColor = $aColor ; + $this->iZFontColor = $aColor ; + } + + function SetFont($aFontFamily,$aFontStyle=FS_NORMAL,$aFontSize=10) { + $this->iFontFamily = $aFontFamily ; + $this->iFontStyle = $aFontStyle ; + $this->iFontSize = $aFontSize ; + $this->SetZFont($aFontFamily,$aFontStyle,$aFontSize); + } + + function SetZFont($aFontFamily,$aFontStyle=FS_NORMAL,$aFontSize=10) { + $this->iZFontFamily = $aFontFamily ; + $this->iZFontStyle = $aFontStyle ; + $this->iZFontSize = $aFontSize ; + } + + function SetZeroLabel($aTxt) { + $this->iLblZeroTxt = $aTxt ; + } + + function SetZFontColor($aColor) { + $this->iZFontColor = $aColor ; + } + + function StrokeLabels($aImg,$xc,$yc,$ri,$rr) { + + if( $this->iHideLabels ) return; + + // Setup some convinient vairables + $a = $this->iAngle * M_PI/180.0; + $n = $this->iNumCirc; + $d = $this->iDelta; + + // Setup the font and font color + $val = new Text(); + $val->SetFont($this->iFontFamily,$this->iFontStyle,$this->iFontSize); + $val->SetColor($this->iFontColor); + + if( $this->iFontBkgColor !== false ) { + $val->SetBox($this->iFontBkgColor,$this->iFontFrameColor); + } + + // Position the labels relative to the radiant circles + if( $this->iLblAlign == LBLALIGN_TOP ) { + if( $a > 0 && $a <= M_PI/2 ) { + $val->SetAlign('left','bottom'); + } + elseif( $a > M_PI/2 && $a <= M_PI ) { + $val->SetAlign('right','bottom'); + } + } + elseif( $this->iLblAlign == LBLALIGN_CENTER ) { + $val->SetAlign('center','center'); + } + + // Stroke the labels close to each circle + $v = $d ; + $si = sin($a); + $co = cos($a); + for( $i=0; $i < $n; ++$i, $v += $d ) { + $r = $ri + ($i+1) * $rr; + $x = $xc + $co * $r; + $y = $yc - $si * $r; + $val->Set(sprintf($this->iLblFmt,$v)); + $val->Stroke($aImg,$x,$y); + } + + // Print the text in the zero circle + if( $this->iLblZeroTxt === null ) { + $this->iLblZeroTxt = sprintf($this->iLblFmt,$this->iZeroSum); + } + else { + $this->iLblZeroTxt = sprintf($this->iLblZeroTxt,$this->iZeroSum); + } + + $val->Set($this->iLblZeroTxt); + $val->SetAlign('center','center'); + $val->SetParagraphAlign('center'); + $val->SetColor($this->iZFontColor); + $val->SetFont($this->iZFontFamily,$this->iZFontStyle,$this->iZFontSize); + $val->Stroke($aImg,$xc,$yc); + } +} + +//=================================================== +// CLASS LegendStyle +//=================================================== +class LegendStyle { + public $iLength = 40, $iMargin = 20 , $iBottomMargin=5; + public $iCircleWeight=2, $iCircleRadius = 18, $iCircleColor='black'; + public $iTxtFontFamily=FF_VERDANA,$iTxtFontStyle=FS_NORMAL,$iTxtFontSize=8; + public $iLblFontFamily=FF_VERDANA,$iLblFontStyle=FS_NORMAL,$iLblFontSize=8; + public $iCircleFontFamily=FF_VERDANA,$iCircleFontStyle=FS_NORMAL,$iCircleFontSize=8; + public $iLblFontColor='black',$iTxtFontColor='black',$iCircleFontColor='black'; + public $iShow=true; + public $iFormatString='%.1f'; + public $iTxtMargin=6, $iTxt=''; + public $iZCircleTxt='Calm'; + + function SetFont($aFontFamily,$aFontStyle=FS_NORMAL,$aFontSize=10) { + $this->iLblFontFamily = $aFontFamily ; + $this->iLblFontStyle = $aFontStyle ; + $this->iLblFontSize = $aFontSize ; + $this->iTxtFontFamily = $aFontFamily ; + $this->iTxtFontStyle = $aFontStyle ; + $this->iTxtFontSize = $aFontSize ; + $this->iCircleFontFamily = $aFontFamily ; + $this->iCircleFontStyle = $aFontStyle ; + $this->iCircleFontSize = $aFontSize ; + } + + function SetLFont($aFontFamily,$aFontStyle=FS_NORMAL,$aFontSize=10) { + $this->iLblFontFamily = $aFontFamily ; + $this->iLblFontStyle = $aFontStyle ; + $this->iLblFontSize = $aFontSize ; + } + + function SetTFont($aFontFamily,$aFontStyle=FS_NORMAL,$aFontSize=10) { + $this->iTxtFontFamily = $aFontFamily ; + $this->iTxtFontStyle = $aFontStyle ; + $this->iTxtFontSize = $aFontSize ; + } + + function SetCFont($aFontFamily,$aFontStyle=FS_NORMAL,$aFontSize=10) { + $this->iCircleFontFamily = $aFontFamily ; + $this->iCircleFontStyle = $aFontStyle ; + $this->iCircleFontSize = $aFontSize ; + } + + + function SetFontColor($aColor) { + $this->iTxtFontColor = $aColor ; + $this->iLblFontColor = $aColor ; + $this->iCircleFontColor = $aColor ; + } + + function SetTFontColor($aColor) { + $this->iTxtFontColor = $aColor ; + } + + function SetLFontColor($aColor) { + $this->iLblFontColor = $aColor ; + } + + function SetCFontColor($aColor) { + $this->iCircleFontColor = $aColor ; + } + + function SetCircleWeight($aWeight) { + $this->iCircleWeight = $aWeight; + } + + function SetCircleRadius($aRadius) { + $this->iCircleRadius = $aRadius; + } + + function SetCircleColor($aColor) { + $this->iCircleColor = $aColor ; + } + + function SetCircleText($aTxt) { + $this->iZCircleTxt = $aTxt; + } + + function SetMargin($aMarg,$aBottomMargin=5) { + $this->iMargin=$aMarg; + $this->iBottomMargin=$aBottomMargin; + } + + function SetLength($aLength) { + $this->iLength = $aLength ; + } + + function Show($aFlg=true) { + $this->iShow = $aFlg; + } + + function Hide($aFlg=true) { + $this->iShow = ! $aFlg; + } + + function SetFormat($aFmt) { + $this->iFormatString=$aFmt; + } + + function SetText($aTxt) { + $this->iTxt = $aTxt ; + } + +} + +define('RANGE_OVERLAPPING',0); +define('RANGE_DISCRETE',1); + +//=================================================== +// CLASS WindrosePlot +//=================================================== +class WindrosePlot { + private $iAntiAlias=true; + private $iData=array(); + public $iX=0.5,$iY=0.5; + public $iSize=0.55; + private $iGridColor1='gray',$iGridColor2='darkgreen'; + private $iRadialColorArray=array(); + private $iRadialWeightArray=array(); + private $iRadialStyleArray=array(); + private $iRanges = array(1,2,3,5,6,10,13.5,99.0); + private $iRangeStyle = RANGE_OVERLAPPING ; + public $iCenterSize=60; + private $iType = WINDROSE_TYPE16; + public $iFontFamily=FF_VERDANA,$iFontStyle=FS_NORMAL,$iFontSize=10; + public $iFontColor='darkgray'; + private $iRadialGridStyle='longdashed'; + private $iAllDirectionLabels = array('E','ENE','NE','NNE','N','NNW','NW','WNW','W','WSW','SW','SSW','S','SSE','SE','ESE'); + private $iStandardDirections = array(); + private $iCircGridWeight=3, $iRadialGridWeight=1; + private $iLabelMargin=12; + private $iLegweights = array(2,4,6,8,10,12,14,16,18,20); + private $iLegColors = array('orange','black','blue','red','green','purple','navy','yellow','brown'); + private $iLabelFormatString='', $iLabels=array(); + private $iLabelPositioning = LBLPOSITION_EDGE; + private $iColor='white'; + private $iShowBox=false, $iBoxColor='black',$iBoxWeight=1,$iBoxStyle='solid'; + private $iOrdinalEncoding=KEYENCODING_ANTICLOCKWISE; + public $legend=null; + + function __construct($aData) { + $this->iData = $aData; + $this->legend = new LegendStyle(); + + // Setup the scale + $this->scale = new WindrosePlotScale($this->iData); + + // default label for free type i agle and a degree sign + $this->iLabelFormatString = '%.1f'.SymChar::Get('degree'); + + $delta = 2*M_PI/16; + for( $i=0, $a=0; $i < 16; ++$i, $a += $delta ) { + $this->iStandardDirections[$this->iAllDirectionLabels[$i]] = $a; + } + } + + // Dummy method to make window plots have the same signature as the + // layout classes since windrose plots are "leaf" classes in the hierarchy + function LayoutSize() { + return 1; + } + + function SetSize($aSize) { + $this->iSize = $aSize; + } + + function SetDataKeyEncoding($aEncoding) { + $this->iOrdinalEncoding = $aEncoding; + } + + function SetColor($aColor) { + $this->iColor = $aColor; + } + + function SetRadialColors($aColors) { + $this->iRadialColorArray = $aColors; + } + + function SetRadialWeights($aWeights) { + $this->iRadialWeightArray = $aWeights; + } + + function SetRadialStyles($aStyles) { + $this->iRadialStyleArray = $aStyles; + } + + function SetBox($aColor='black',$aWeight=1, $aStyle='solid', $aShow=true) { + $this->iShowBox = $aShow ; + $this->iBoxColor = $aColor ; + $this->iBoxWeight = $aWeight ; + $this->iBoxStyle = $aStyle; + } + + function SetLabels($aLabels) { + $this->iLabels = $aLabels ; + } + + function SetLabelMargin($aMarg) { + $this->iLabelMargin = $aMarg ; + } + + function SetLabelFormat($aLblFormat) { + $this->iLabelFormatString = $aLblFormat ; + } + + function SetCompassLabels($aLabels) { + if( count($aLabels) != 16 ) { + JpgraphError::RaiseL(22004); //('Label specification for windrose directions must have 16 values (one for each compass direction).'); + } + $this->iAllDirectionLabels = $aLabels ; + + $delta = 2*M_PI/16; + for( $i=0, $a=0; $i < 16; ++$i, $a += $delta ) { + $this->iStandardDirections[$this->iAllDirectionLabels[$i]] = $a; + } + + } + + function SetCenterSize($aSize) { + $this->iCenterSize = $aSize; + } + // Alias for SetCenterSize + function SetZCircleSize($aSize) { + $this->iCenterSize = $aSize; + } + + function SetFont($aFFam,$aFStyle=FS_NORMAL,$aFSize=10) { + $this->iFontFamily = $aFFam ; + $this->iFontStyle = $aFStyle ; + $this->iFontSize = $aFSize ; + } + + function SetFontColor($aColor) { + $this->iFontColor=$aColor; + } + + function SetGridColor($aColor1,$aColor2) { + $this->iGridColor1 = $aColor1; + $this->iGridColor2 = $aColor2; + } + + function SetGridWeight($aGrid1=1,$aGrid2=2) { + $this->iCircGridWeight = $aGrid1 ; + $this->iRadialGridWeight = $aGrid2 ; + } + + function SetRadialGridStyle($aStyle) { + $aStyle = strtolower($aStyle); + if( !in_array($aStyle,array('solid','dotted','dashed','longdashed')) ) { + JpGraphError::RaiseL(22005); //("Line style for radial lines must be on of ('solid','dotted','dashed','longdashed') "); + } + $this->iRadialGridStyle=$aStyle; + } + + function SetRanges($aRanges) { + $this->iRanges = $aRanges; + } + + function SetRangeStyle($aStyle) { + $this->iRangeStyle = $aStyle; + } + + function SetRangeColors($aLegColors) { + $this->iLegColors = $aLegColors; + } + + function SetRangeWeights($aWeights) { + $n=count($aWeights); + for($i=0; $i< $n; ++$i ) { + $aWeights[$i] = floor($aWeights[$i]/2); + } + $this->iLegweights = $aWeights; + + } + + function SetType($aType) { + if( $aType < WINDROSE_TYPE4 || $aType > WINDROSE_TYPEFREE ) { + JpGraphError::RaiseL(22006); //('Illegal windrose type specified.'); + } + $this->iType = $aType; + } + + // Alias for SetPos() + function SetCenterPos($aX,$aY) { + $this->iX = $aX; + $this->iY = $aY; + } + + function SetPos($aX,$aY) { + $this->iX = $aX; + $this->iY = $aY; + } + + function SetAntiAlias($aFlag) { + $this->iAntiAlias = $aFlag ; + if( ! $aFlag ) + $this->iCircGridWeight = 1; + } + + function _ThickCircle($aImg,$aXC,$aYC,$aRad,$aWeight=2,$aColor) { + + $aImg->SetColor($aColor); + $aRad *= 2 ; + $aImg->Ellipse($aXC,$aYC,$aRad,$aRad); + if( $aWeight > 1 ) { + $aImg->Ellipse($aXC,$aYC,$aRad+1,$aRad+1); + $aImg->Ellipse($aXC,$aYC,$aRad+2,$aRad+2); + if( $aWeight > 2 ) { + $aImg->Ellipse($aXC,$aYC,$aRad+3,$aRad+3); + $aImg->Ellipse($aXC,$aYC,$aRad+3,$aRad+4); + $aImg->Ellipse($aXC,$aYC,$aRad+4,$aRad+3); + } + } + } + + function _StrokeWindLeg($aImg,$xc,$yc,$a,$ri,$r,$weight,$color) { + + // If less than 1 px long then we assume this has been caused by rounding problems + // and should not be stroked + if( $r < 1 ) return; + + $xt = $xc + cos($a)*$ri; + $yt = $yc - sin($a)*$ri; + $xxt = $xc + cos($a)*($ri+$r); + $yyt = $yc - sin($a)*($ri+$r); + + $x1 = $xt - $weight*sin($a); + $y1 = $yt - $weight*cos($a); + $x2 = $xxt - $weight*sin($a); + $y2 = $yyt - $weight*cos($a); + + $x3 = $xxt + $weight*sin($a); + $y3 = $yyt + $weight*cos($a); + $x4 = $xt + $weight*sin($a); + $y4 = $yt + $weight*cos($a); + + $pts = array($x1,$y1,$x2,$y2,$x3,$y3,$x4,$y4); + $aImg->SetColor($color); + $aImg->FilledPolygon($pts); + + } + + function _StrokeLegend($aImg,$x,$y,$scaling=1,$aReturnWidth=false) { + + if( ! $this->legend->iShow ) return 0; + + $nlc = count($this->iLegColors); + $nlw = count($this->iLegweights); + + // Setup font for ranges + $value = new Text(); + $value->SetAlign('center','bottom'); + $value->SetFont($this->legend->iLblFontFamily, + $this->legend->iLblFontStyle, + $this->legend->iLblFontSize*$scaling); + $value->SetColor($this->legend->iLblFontColor); + + // Remember x-center + $xcenter = $x ; + + // Construct format string + $fmt = $this->legend->iFormatString.'-'.$this->legend->iFormatString; + + // Make sure that the length of each range is enough to cover the + // size of the labels + $tst = sprintf($fmt,$this->iRanges[0],$this->iRanges[1]); + $value->Set($tst); + $w = $value->GetWidth($aImg); + $l = round(max($this->legend->iLength * $scaling,$w*1.5)); + + $r = $this->legend->iCircleRadius * $scaling ; + $len = 2*$r + $this->scale->iMaxNum * $l; + + // We are called just to find out the width + if( $aReturnWidth ) return $len; + + $x -= round($len/2); + $x += $r; + + // 4 pixels extra vertical margin since the circle sometimes is +/- 1 pixel of the + // theorethical radius due to imperfection in the GD library + //$y -= round(max($r,$scaling*$this->iLegweights[($this->scale->iMaxNum-1) % $nlw])+4*$scaling); + $y -= ($this->legend->iCircleRadius + 2)*$scaling+$this->legend->iBottomMargin*$scaling; + + // Adjust for bottom text + if( $this->legend->iTxt != '' ) { + // Setup font for text + $value->Set($this->legend->iTxt); + $y -= /*$this->legend->iTxtMargin + */ $value->GetHeight($aImg); + } + + // Stroke 0-circle + $this->_ThickCircle($aImg,$x,$y,$r,$this->legend->iCircleWeight, + $this->legend->iCircleColor); + + // Remember the center of the circe + $xc=$x; $yc=$y; + + $value->SetAlign('center','bottom'); + $x += $r+1; + + // Stroke all used ranges + $txty = $y - + round($this->iLegweights[($this->scale->iMaxNum-1)%$nlw]*$scaling) - 4*$scaling; + if( $this->scale->iMaxNum >= count($this->iRanges) ) { + JpGraphError::RaiseL(22007); //('To few values for the range legend.'); + } + $i=0;$idx=0; + while( $i < $this->scale->iMaxNum ) { + $y1 = $y - round($this->iLegweights[$i % $nlw]*$scaling); + $y2 = $y + round($this->iLegweights[$i % $nlw]*$scaling); + $x2 = $x + $l ; + $aImg->SetColor($this->iLegColors[$i % $nlc]); + $aImg->FilledRectangle($x,$y1,$x2,$y2); + if( $this->iRangeStyle == RANGE_OVERLAPPING ) { + $lbl = sprintf($fmt,$this->iRanges[$idx],$this->iRanges[$idx+1]); + } + else { + $lbl = sprintf($fmt,$this->iRanges[$idx],$this->iRanges[$idx+1]); + ++$idx; + } + $value->Set($lbl); + $value->Stroke($aImg,$x+$l/2,$txty); + $x = $x2; + ++$i;++$idx; + } + + // Setup circle font + $value->SetFont($this->legend->iCircleFontFamily, + $this->legend->iCircleFontStyle, + $this->legend->iCircleFontSize*$scaling); + $value->SetColor($this->legend->iCircleFontColor); + + // Stroke 0-circle text + $value->Set($this->legend->iZCircleTxt); + $value->SetAlign('center','center'); + $value->ParagraphAlign('center'); + $value->Stroke($aImg,$xc,$yc); + + // Setup circle font + $value->SetFont($this->legend->iTxtFontFamily, + $this->legend->iTxtFontStyle, + $this->legend->iTxtFontSize*$scaling); + $value->SetColor($this->legend->iTxtFontColor); + + // Draw the text under the legend + $value->Set($this->legend->iTxt); + $value->SetAlign('center','top'); + $value->SetParagraphAlign('center'); + $value->Stroke($aImg,$xcenter,$y2+$this->legend->iTxtMargin*$scaling); + } + + function SetAutoScaleAngle($aIsRegRose=true) { + + // If the user already has manually set an angle don't + // trye to find a position + if( is_numeric($this->scale->iAngle) ) + return; + + if( $aIsRegRose ) { + + // Create a complete data for all directions + // and translate string directions to ordinal values. + // This will much simplify the logic below + for( $i=0; $i < 16; ++$i ) { + $dtxt = $this->iAllDirectionLabels[$i]; + if( !empty($this->iData[$dtxt]) ) { + $data[$i] = $this->iData[$dtxt]; + } + elseif( !empty($this->iData[strtolower($dtxt)]) ) { + $data[$i] = $this->iData[strtolower($dtxt)]; + } + elseif( !empty($this->iData[$i]) ) { + $data[$i] = $this->iData[$i]; + } + else { + $data[$i] = array(); + } + } + + // Find the leg which has the lowest weighted sum of number of data around it + $c0 = array_sum($data[0]); + $c1 = array_sum($data[1]); + $found = 1; + $min = $c0+$c1*100; // Initialize to a high value + for( $i=1; $i < 15; ++$i ) { + $c2 = array_sum($data[$i+1]); + + // Weight the leg we will use more to give preference + // to a short middle leg even if the 3 way sum is similair + $w = $c0 + 3*$c1 + $c2 ; + if( $w < $min ) { + $min = $w; + $found = $i; + } + $c0 = $c1; + $c1 = $c2; + } + $this->scale->iAngle = $found*22.5; + } + else { + $n = count($this->iData); + foreach( $this->iData as $dir => $leg ) { + if( !is_numeric($dir) ) { + $pos = array_search(strtoupper($dir),$this->iAllDirectionLabels); + if( $pos !== false ) { + $dir = $pos*22.5; + } + } + $data[round($dir)] = $leg; + } + + // Get all the angles for the data and sort it + $keys = array_keys($data); + sort($keys, SORT_NUMERIC); + + $n = count($data); + $found = false; + $max = 0 ; + for( $i=0; $i < 15; ++$i ) { + $try_a = round(22.5*$i); + + if( $try_a > $keys[$n-1] ) break; + + if( in_array($try_a,$keys) ) continue; + + // Find the angle just lower than this + $j=0; + while( $j < $n && $keys[$j] <= $try_a ) ++$j; + if( $j == 0 ) { + $kj = 0; $keys[$n-1]; + $d1 = 0; abs($kj-$try_a); + } + else { + --$j; + $kj = $keys[$j]; + $d1 = abs($kj-$try_a); + } + + // Find the angle just larger than this + $l=$n-1; + while( $l >= 0 && $keys[$l] >= $try_a ) --$l; + if( $l == $n-1) { + $kl = $keys[0]; + $d2 = abs($kl-$try_a); + } + else { + ++$l; + $kl = $keys[$l]; + $d2 = abs($kl-$try_a); + } + + // Weight the distance so that legs with large spread + // gets a better weight + $w = $d1 + $d2; + if( $i == 0 ) { + $w = round(1.4 * $w); + } + $diff = abs($d1 - $d2); + $w *= (360-$diff); + if( $w > $max ) { + $found = $i; + $max = $w; + } + } + + $a = $found*22.5; + + // Some heuristics to have some preferred positions + if( $keys[$n-1] < 25 ) $a = 45; + elseif( $keys[0] > 60 ) $a = 45; + elseif( $keys[0] > 25 && $keys[$n-1] < 340 ) $a = 0; + elseif( $keys[$n-1] < 75 ) $a = 90; + elseif( $keys[$n-1] < 120 ) $a = 135; + elseif( $keys[$n-1] < 160 ) $a = 180; + + $this->scale->iAngle = $a ; + } + } + + function NormAngle($a) { + while( $a > 360 ) { + $a -= 360; + } + return $a; + } + + function SetLabelPosition($aPos) { + $this->iLabelPositioning = $aPos ; + } + + function _StrokeFreeRose($dblImg,$value,$scaling,$xc,$yc,$r,$ri) { + + // Plot radial grid lines and remember the end position + // and the angle for later use when plotting the labels + if( $this->iType != WINDROSE_TYPEFREE ) { + JpGraphError::RaiseL(22008); //('Internal error: Trying to plot free Windrose even though type is not a free windorose'); + } + + // Check if we should auto-position the angle for the + // labels. Basically we try to find a firection with smallest + // (or none) data. + $this->SetAutoScaleAngle(false); + + $nlc = count($this->iLegColors); + $nlw = count($this->iLegweights); + + // Stroke grid lines for directions and remember the + // position for the labels + $txtpos=array(); + $num = count($this->iData); + + $keys = array_keys($this->iData); + + foreach( $this->iData as $dir => $legdata ) { + if( in_array($dir,$this->iAllDirectionLabels,true) === true) { + $a = $this->iStandardDirections[strtoupper($dir)]; + if( in_array($a*180/M_PI,$keys) ) { + JpGraphError::RaiseL(22009,round($a*180/M_PI)); + //('You have specified the same direction twice, once with an angle and once with a compass direction ('.$a*180/M_PI.' degrees.)'); + } + } + elseif( is_numeric($dir) ) { + $this->NormAngle($dir); + + if( $this->iOrdinalEncoding == KEYENCODING_CLOCKWISE ) { + $dir = 360-$dir; + } + + $a = $dir * M_PI/180; + } + else { + JpGraphError::RaiseL(22010);//('Direction must either be a numeric value or one of the 16 compass directions'); + } + + $xxc = round($xc + cos($a)*$ri); + $yyc = round($yc - sin($a)*$ri); + $x = round($xc + cos($a)*$r); + $y = round($yc - sin($a)*$r); + if( empty($this->iRadialColorArray[$dir]) ) { + $dblImg->SetColor($this->iGridColor2); + } + else { + $dblImg->SetColor($this->iRadialColorArray[$dir]); + } + if( empty($this->iRadialWeightArray[$dir]) ) { + $dblImg->SetLineWeight($this->iRadialGridWeight); + } + else { + $dblImg->SetLineWeight($this->iRadialWeightArray[$dir]); + } + if( empty($this->iRadialStyleArray[$dir]) ) { + $dblImg->SetLineStyle($this->iRadialGridStyle); + } + else { + $dblImg->SetLineStyle($this->iRadialStyleArray[$dir]); + } + $dblImg->StyleLine($xxc,$yyc,$x,$y); + $txtpos[] = array($x,$y,$a); + } + $dblImg->SetLineWeight(1); + + // Setup labels + $lr = $scaling * $this->iLabelMargin; + + if( $this->iLabelPositioning == LBLPOSITION_EDGE ) { + $value->SetAlign('left','top'); + } + else { + $value->SetAlign('center','center'); + $value->SetMargin(0); + } + + for($i=0; $i < $num; ++$i ) { + + list($x,$y,$a) = $txtpos[$i]; + + // Determine the label + + $da = $a*180/M_PI; + if( $this->iOrdinalEncoding == KEYENCODING_CLOCKWISE ) { + $da = 360 - $da; + } + + //$da = 360-$da; + + if( !empty($this->iLabels[$keys[$i]]) ) { + $lbl = $this->iLabels[$keys[$i]]; + } + else { + $lbl = sprintf($this->iLabelFormatString,$da); + } + + if( $this->iLabelPositioning == LBLPOSITION_CENTER ) { + $dx = $dy = 0; + } + else { + // LBLPOSIITON_EDGE + if( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0; + if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI; + if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1; + if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI); + + if( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI; + if( $a<=M_PI/4 ) $dy=(0.5+$a*2/M_PI); + if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1; + if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI); + if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0; + } + + $value->Set($lbl); + $th = $value->GetHeight($dblImg); + $tw = $value->GetWidth($dblImg); + $xt=round($lr*cos($a)+$x) - $dx*$tw; + $yt=round($y-$lr*sin($a)) - $dy*$th; + + $value->Stroke($dblImg,$xt,$yt); + } + + if( __DEBUG ) { + $dblImg->SetColor('red'); + $dblImg->Circle($xc,$yc,$lr+$r); + } + + // Stroke all the legs + reset($this->iData); + $i=0; + foreach($this->iData as $dir => $legdata) { + $legdata = array_slice($legdata,1); + $nn = count($legdata); + + $a = $txtpos[$i][2]; + $rri = $ri/$scaling; + for( $j=0; $j < $nn; ++$j ) { + // We want the non scaled original radius + $legr = $this->scale->RelTranslate($legdata[$j],$r/$scaling,$ri/$scaling) ; + $this->_StrokeWindLeg($dblImg, $xc, $yc, $a, + $rri *$scaling, + $legr *$scaling, + $this->iLegweights[$j % $nlw] * $scaling, + $this->iLegColors[$j % $nlc]); + $rri += $legr; + } + ++$i; + } + } + + // Translate potential string specified compass labels to their + // corresponding index. + function FixupIndexes($aDataArray,$num) { + $ret = array(); + $keys = array_keys($aDataArray); + foreach($aDataArray as $idx => $data) { + if( is_string($idx) ) { + $idx = strtoupper($idx); + $res = array_search($idx,$this->iAllDirectionLabels); + if( $res === false ) { + JpGraphError::RaiseL(22011,$idx); //('Windrose index must be numeric or direction label. You have specified index='.$idx); + } + $idx = $res; + if( $idx % (16 / $num) !== 0 ) { + JpGraphError::RaiseL(22012); //('Windrose radial axis specification contains a direction which is not enabled.'); + } + $idx /= (16/$num) ; + + if( in_array($idx,$keys,1) ) { + JpgraphError::RaiseL(22013,$idx); //('You have specified the look&feel for the same compass direction twice, once with text and once with index (Index='.$idx.')'); + } + } + if( $idx < 0 || $idx > 15 ) { + JpgraphError::RaiseL(22014); //('Index for copmass direction must be between 0 and 15.'); + } + $ret[$idx] = $data; + } + return $ret; + } + + function _StrokeRegularRose($dblImg,$value,$scaling,$xc,$yc,$r,$ri) { + // _StrokeRegularRose($dblImg,$xc,$yc,$r,$ri) + // Plot radial grid lines and remember the end position + // and the angle for later use when plotting the labels + switch( $this->iType ) { + case WINDROSE_TYPE4: + $num = 4; break; + case WINDROSE_TYPE8: + $num = 8; break; + case WINDROSE_TYPE16: + $num = 16; break; + default: + JpGraphError::RaiseL(22015);//('You have specified an undefined Windrose plot type.'); + } + + // Check if we should auto-position the angle for the + // labels. Basically we try to find a firection with smallest + // (or none) data. + $this->SetAutoScaleAngle(true); + + $nlc = count($this->iLegColors); + $nlw = count($this->iLegweights); + + $this->iRadialColorArray = $this->FixupIndexes($this->iRadialColorArray,$num); + $this->iRadialWeightArray = $this->FixupIndexes($this->iRadialWeightArray,$num); + $this->iRadialStyleArray = $this->FixupIndexes($this->iRadialStyleArray,$num); + + $txtpos=array(); + $a = 2*M_PI/$num; + $dblImg->SetColor($this->iGridColor2); + $dblImg->SetLineStyle($this->iRadialGridStyle); + $dblImg->SetLineWeight($this->iRadialGridWeight); + + // Translate any name specified directions to the index + // so we can easily use it in the loop below + for($i=0; $i < $num; ++$i ) { + $xxc = round($xc + cos($a*$i)*$ri); + $yyc = round($yc - sin($a*$i)*$ri); + $x = round($xc + cos($a*$i)*$r); + $y = round($yc - sin($a*$i)*$r); + if( empty($this->iRadialColorArray[$i]) ) { + $dblImg->SetColor($this->iGridColor2); + } + else { + $dblImg->SetColor($this->iRadialColorArray[$i]); + } + if( empty($this->iRadialWeightArray[$i]) ) { + $dblImg->SetLineWeight($this->iRadialGridWeight); + } + else { + $dblImg->SetLineWeight($this->iRadialWeightArray[$i]); + } + if( empty($this->iRadialStyleArray[$i]) ) { + $dblImg->SetLineStyle($this->iRadialGridStyle); + } + else { + $dblImg->SetLineStyle($this->iRadialStyleArray[$i]); + } + + $dblImg->StyleLine($xxc,$yyc,$x,$y); + $txtpos[] = array($x,$y,$a*$i); + } + $dblImg->SetLineWeight(1); + + $lr = $scaling * $this->iLabelMargin; + if( $this->iLabelPositioning == LBLPOSITION_CENTER ) { + $value->SetAlign('center','center'); + } + else { + $value->SetAlign('left','top'); + $value->SetMargin(0); + $lr /= 2 ; + } + + for($i=0; $i < $num; ++$i ) { + list($x,$y,$a) = $txtpos[$i]; + + // Set the position of the label + if( $this->iLabelPositioning == LBLPOSITION_CENTER ) { + $dx = $dy = 0; + } + else { + // LBLPOSIITON_EDGE + if( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0; + if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI; + if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1; + if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI); + + if( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI; + if( $a<=M_PI/4 ) $dy=(0.5+$a*2/M_PI); + if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1; + if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI); + if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0; + } + + $value->Set($this->iAllDirectionLabels[$i*(16/$num)]); + $th = $value->GetHeight($dblImg); + $tw = $value->GetWidth($dblImg); + $xt=round($lr*cos($a)+$x) - $dx*$tw; + $yt=round($y-$lr*sin($a)) - $dy*$th; + + $value->Stroke($dblImg,$xt,$yt); + } + + if( __DEBUG ) { + $dblImg->SetColor("red"); + $dblImg->Circle($xc,$yc,$lr+$r); + } + + // Stroke all the legs + reset($this->iData); + $keys = array_keys($this->iData); + foreach($this->iData as $idx => $legdata) { + $legdata = array_slice($legdata,1); + $nn = count($legdata); + if( is_string($idx) ) { + $idx = strtoupper($idx); + $idx = array_search($idx,$this->iAllDirectionLabels); + if( $idx === false ) { + JpGraphError::RaiseL(22016);//('Windrose leg index must be numeric or direction label.'); + } + if( $idx % (16 / $num) !== 0 ) { + JpGraphError::RaiseL(22017);//('Windrose data contains a direction which is not enabled. Please adjust what labels are displayed.'); + } + $idx /= (16/$num) ; + + if( in_array($idx,$keys,1) ) { + JpgraphError::RaiseL(22018,$idx);//('You have specified data for the same compass direction twice, once with text and once with index (Index='.$idx.')'); + + } + } + if( $idx < 0 || $idx > 15 ) { + JpgraphError::RaiseL(22019);//('Index for direction must be between 0 and 15. You can\'t specify angles for a Regular Windplot, only index and compass directions.'); + } + $a = $idx * (360 / $num) ; + $a *= M_PI/180.0; + $rri = $ri/$scaling; + for( $j=0; $j < $nn; ++$j ) { + // We want the non scaled original radius + $legr = $this->scale->RelTranslate($legdata[$j], $r/$scaling,$ri/$scaling) ; + $this->_StrokeWindLeg($dblImg, $xc, $yc, $a, + $rri *$scaling, + $legr *$scaling, + $this->iLegweights[$j % $nlw] * $scaling, + $this->iLegColors[$j % $nlc]); + $rri += $legr; + } + } + } + + + function getWidth($aImg) { + + $scaling = 1;//$this->iAntiAlias ? 2 : 1 ; + if( $this->iSize > 0 && $this->iSize < 1 ) { + $this->iSize *= min($aImg->width,$aImg->height); + } + + + $value = new Text(); + $value->SetFont($this->iFontFamily,$this->iFontStyle,$this->iFontSize*$scaling); + $value->SetColor($this->iFontColor); + // Setup extra size around the graph needed so that the labels + // doesn't get cut. For this we need to find the largest label. + // The code below gives a possible a little to large margin. The + // really, really proper way would be to account for what angle + // the label are at + $n = count($this->iLabels); + if( $n > 0 ) { + $maxh=0;$maxw=0; + foreach($this->iLabels as $key => $lbl) { + $value->Set($lbl); + $maxw = max($maxw,$value->GetWidth($aImg)); + } + } + else { + $value->Set('888.888'); // Dummy value to get width/height + $maxw = $value->GetWidth($aImg); + } + // Add an extra margin of 50% the font size + $maxw += round($this->iFontSize*$scaling * 0.4) ; + + $valxmarg = 1.5*$maxw+2*$this->iLabelMargin*$scaling; + $w = round($this->iSize*$scaling + $valxmarg); + + // Make sure that the width of the legend fits + $legendwidth = $this->_StrokeLegend($aImg,0,0,$scaling,true)+10*$scaling; + $w = max($w,$legendwidth); + + return $w; + } + + function getHeight($aImg) { + + $scaling = 1;//$this->iAntiAlias ? 2 : 1 ; + if( $this->iSize > 0 && $this->iSize < 1 ) { + $this->iSize *= min($aImg->width,$aImg->height); + } + + $value = new Text(); + $value->SetFont($this->iFontFamily,$this->iFontStyle,$this->iFontSize*$scaling); + $value->SetColor($this->iFontColor); + // Setup extra size around the graph needed so that the labels + // doesn't get cut. For this we need to find the largest label. + // The code below gives a possible a little to large margin. The + // really, really proper way would be to account for what angle + // the label are at + $n = count($this->iLabels); + if( $n > 0 ) { + $maxh=0;$maxw=0; + foreach($this->iLabels as $key => $lbl) { + $value->Set($lbl); + $maxh = max($maxh,$value->GetHeight($aImg)); + } + } + else { + $value->Set('180.8'); // Dummy value to get width/height + $maxh = $value->GetHeight($aImg); + } + // Add an extra margin of 50% the font size + //$maxh += round($this->iFontSize*$scaling * 0.5) ; + $valymarg = 2*$maxh+2*$this->iLabelMargin*$scaling; + + $legendheight = round($this->legend->iShow ? 1 : 0); + $legendheight *= max($this->legend->iCircleRadius*2,$this->legend->iTxtFontSize*2)+ + $this->legend->iMargin + $this->legend->iBottomMargin + 2; + $legendheight *= $scaling; + $h = round($this->iSize*$scaling + $valymarg) + $legendheight ; + + return $h; + } + + function Stroke($aGraph) { + + $aImg = $aGraph->img; + + if( $this->iX > 0 && $this->iX < 1 ) { + $this->iX = round( $aImg->width * $this->iX ) ; + } + + if( $this->iY > 0 && $this->iY < 1 ) { + $this->iY = round( $aImg->height * $this->iY ) ; + } + + if( $this->iSize > 0 && $this->iSize < 1 ) { + $this->iSize *= min($aImg->width,$aImg->height); + } + + if( $this->iCenterSize > 0 && $this->iCenterSize < 1 ) { + $this->iCenterSize *= $this->iSize; + } + + $this->scale->AutoScale(($this->iSize - $this->iCenterSize)/2, round(2.5*$this->scale->iFontSize)); + + $scaling = $this->iAntiAlias ? 2 : 1 ; + + $value = new Text(); + $value->SetFont($this->iFontFamily,$this->iFontStyle,$this->iFontSize*$scaling); + $value->SetColor($this->iFontColor); + + $legendheight = round($this->legend->iShow ? 1 : 0); + $legendheight *= max($this->legend->iCircleRadius*2,$this->legend->iTxtFontSize*2)+ + $this->legend->iMargin + $this->legend->iBottomMargin + 2; + $legendheight *= $scaling; + + $w = $scaling*$this->getWidth($aImg); + $h = $scaling*$this->getHeight($aImg); + + // Copy back the double buffered image to the proper canvas + $ww = $w / $scaling ; + $hh = $h / $scaling ; + + // Create the double buffer + if( $this->iAntiAlias ) { + $dblImg = new RotImage($w,$h); + // Set the background color + $dblImg->SetColor($this->iColor); + $dblImg->FilledRectangle(0,0,$w,$h); + } + else { + $dblImg = $aImg ; + // Make sure the ix and it coordinates correpond to the new top left center + $dblImg->SetTranslation($this->iX-$w/2, $this->iY-$h/2); + } + + if( __DEBUG ) { + $dblImg->SetColor('red'); + $dblImg->Rectangle(0,0,$w-1,$h-1); + } + + $dblImg->SetColor('black'); + + if( $this->iShowBox ) { + $dblImg->SetColor($this->iBoxColor); + $old = $dblImg->SetLineWeight($this->iBoxWeight); + $dblImg->SetLineStyle($this->iBoxStyle); + $dblImg->Rectangle(0,0,$w-1,$h-1); + $dblImg->SetLineWeight($old); + } + + $xc = round($w/2); + $yc = round(($h-$legendheight)/2); + + if( __DEBUG ) { + $dblImg->SetColor('red'); + $old = $dblImg->SetLineWeight(2); + $dblImg->Line($xc-5,$yc-5,$xc+5,$yc+5); + $dblImg->Line($xc+5,$yc-5,$xc-5,$yc+5); + $dblImg->SetLineWeight($old); + } + + $this->iSize *= $scaling; + + // Inner circle size + $ri = $this->iCenterSize/2 ; + + // Full circle radius + $r = round( $this->iSize/2 ); + + // Get number of grid circles + $n = $this->scale->GetNumCirc(); + + // Plot circle grids + $ri *= $scaling ; + $rr = round(($r-$ri)/$n); + for( $i = 1; $i <= $n; ++$i ) { + $this->_ThickCircle($dblImg,$xc,$yc,$rr*$i+$ri, + $this->iCircGridWeight,$this->iGridColor1); + } + + $num = 0 ; + + if( $this->iType == WINDROSE_TYPEFREE ) { + $this->_StrokeFreeRose($dblImg,$value,$scaling,$xc,$yc,$r,$ri); + } + else { + // Check if we need to re-code the interpretation of the ordinal + // number in the data. Internally ordinal value 0 is East and then + // counted anti-clockwise. The user might choose an encoding + // that have 0 being the first axis to the right of the "N" axis and then + // counted clock-wise + if( $this->iOrdinalEncoding == KEYENCODING_CLOCKWISE ) { + if( $this->iType == WINDROSE_TYPE16 ) { + $const1 = 19; $const2 = 16; + } + elseif( $this->iType == WINDROSE_TYPE8 ) { + $const1 = 9; $const2 = 8; + } + else { + $const1 = 4; $const2 = 4; + } + $tmp = array(); + $n=count($this->iData); + foreach( $this->iData as $key => $val ) { + if( is_numeric($key) ) { + $key = ($const1 - $key) % $const2 ; + } + $tmp[$key] = $val; + } + $this->iData = $tmp; + } + $this->_StrokeRegularRose($dblImg,$value,$scaling,$xc,$yc,$r,$ri); + } + + // Stroke the labels + $this->scale->iFontSize *= $scaling; + $this->scale->iZFontSize *= $scaling; + $this->scale->StrokeLabels($dblImg,$xc,$yc,$ri,$rr); + + // Stroke the inner circle again since the legs + // might have written over it + $this->_ThickCircle($dblImg,$xc,$yc,$ri,$this->iCircGridWeight,$this->iGridColor1); + + if( $ww > $aImg->width ) { + JpgraphError::RaiseL(22020); + //('Windrose plot is too large to fit the specified Graph size. Please use WindrosePlot::SetSize() to make the plot smaller or increase the size of the Graph in the initial WindroseGraph() call.'); + } + + $x = $xc; + $y = $h; + $this->_StrokeLegend($dblImg,$x,$y,$scaling); + + if( $this->iAntiAlias ) { + $aImg->Copy($dblImg->img, $this->iX-$ww/2, $this->iY-$hh/2, 0, 0, $ww,$hh, $w,$h); + } + + // We need to restore the translation matrix + $aImg->SetTranslation(0,0); + + } + +} + +//============================================================ +// CLASS WindroseGraph +//============================================================ +class WindroseGraph extends Graph { + private $posx, $posy; + public $plots=array(); + + function __construct($width=300,$height=200,$cachedName="",$timeout=0,$inline=1) { + parent::__construct($width,$height,$cachedName,$timeout,$inline); + $this->posx=$width/2; + $this->posy=$height/2; + $this->SetColor('white'); + $this->title->SetFont(FF_VERDANA,FS_NORMAL,12); + $this->title->SetMargin(8); + $this->subtitle->SetFont(FF_VERDANA,FS_NORMAL,10); + $this->subtitle->SetMargin(0); + $this->subsubtitle->SetFont(FF_VERDANA,FS_NORMAL,8); + $this->subsubtitle->SetMargin(0); + } + + function StrokeTexts() { + if( $this->texts != null ) { + $n = count($this->texts); + for($i=0; $i < $n; ++$i ) { + $this->texts[$i]->Stroke($this->img); + } + } + } + + function StrokeIcons() { + if( $this->iIcons != null ) { + $n = count($this->iIcons); + for( $i=0; $i < $n; ++$i ) { + // Since Windrose graphs doesn't have any linear scale the position of + // each icon has to be given as absolute coordinates + $this->iIcons[$i]->_Stroke($this->img); + } + } + } + + //--------------- + // PUBLIC METHODS + function Add($aObj) { + if( is_array($aObj) && count($aObj) > 0 ) { + $cl = $aObj[0]; + } + else { + $cl = $aObj; + } + if( $cl instanceof Text ) { + $this->AddText($aObj); + } + elseif( $cl instanceof IconPlot ) { + $this->AddIcon($aObj); + } + elseif( ($cl instanceof WindrosePlot) || ($cl instanceof LayoutRect) || ($cl instanceof LayoutHor)) { + $this->plots[] = $aObj; + } + else { + JpgraphError::RaiseL(22021); + } + } + + function AddText($aTxt,$aToY2=false) { + parent::AddText($aTxt); + } + + function SetColor($c) { + $this->SetMarginColor($c); + } + + // Method description + function Stroke($aStrokeFileName="") { + + // If the filename is the predefined value = '_csim_special_' + // we assume that the call to stroke only needs to do enough + // to correctly generate the CSIM maps. + // We use this variable to skip things we don't strictly need + // to do to generate the image map to improve performance + // as best we can. Therefore you will see a lot of tests !$_csim in the + // code below. + $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); + + // We need to know if we have stroked the plot in the + // GetCSIMareas. Otherwise the CSIM hasn't been generated + // and in the case of GetCSIM called before stroke to generate + // CSIM without storing an image to disk GetCSIM must call Stroke. + $this->iHasStroked = true; + + if( $this->background_image != "" || $this->background_cflag != "" ) { + $this->StrokeFrameBackground(); + } + else { + $this->StrokeFrame(); + } + + // n holds number of plots + $n = count($this->plots); + for($i=0; $i < $n ; ++$i) { + $this->plots[$i]->Stroke($this); + } + + $this->footer->Stroke($this->img); + $this->StrokeIcons(); + $this->StrokeTexts(); + $this->StrokeTitles(); + + // If the filename is given as the special "__handle" + // then the image handler is returned and the image is NOT + // streamed back + if( $aStrokeFileName == _IMG_HANDLER ) { + return $this->img->img; + } + else { + // Finally stream the generated picture + $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline, + $aStrokeFileName); + } + } + +} // Class + +?> diff --git a/src/classes/jpgraph/lang/de.inc.php b/src/classes/jpgraph/lang/de.inc.php index c92e549..37ba264 100644 --- a/src/classes/jpgraph/lang/de.inc.php +++ b/src/classes/jpgraph/lang/de.inc.php @@ -186,7 +186,8 @@ HTTP header wurden bereits gesendet.
Fehler in der Datei %s in der Zei 15008 => array('PiePlot::SetLabelType() der Typ für Tortendiagramme muss entweder 0 or 1 sein (nicht %d).',1), 15009 => array('Ungültiges Tortendiagramm. Die Summe aller Daten ist Null.',0), 15010 => array('Die Summe aller Daten ist Null.',0), -15011 => array('Um Bildtransformationen benutzen zu können, muss die Datei jpgraph_imgtrans.php eingefügt werden (per include).',0), +15011 => array('Um Bildtransformationen benutzen zu können, muss die Datei jpgraph_imgtrans.php eingefügt werden (per include).',0), // @todo translate into German +15012 => array('PiePlot::SetTheme() is no longer recommended. Use PieGraph::SetTheme()',0), /* ** jpgraph_plotband @@ -405,6 +406,8 @@ HTTP header wurden bereits gesendet.
Fehler in der Datei %s in der Zei 25130 => array('Too small plot area. (%d x %d). With the given image size and margins there is to little space left for the plot. Increase the plot size or reduce the margins.',2), 25131 => array('StrokeBoxedText2() only supports TTF fonts and not built-in bitmap fonts.',0), +25132 => array('Undefined property %s.',1), // @todo translate +25133 => array('Use Graph::SetTheme() after Graph::SetScale().',0), // @todo translate /* ** jpgraph_led @@ -537,6 +540,13 @@ HTTP header wurden bereits gesendet.
Fehler in der Datei %s in der Zei 29209 => array('CSIM Target matrix must be the same size as the data matrix (csim=%d x %d, data=%d x %d)',4), 29210 => array('CSIM Target for matrix labels does not match the number of labels (csim=%d, labels=%d)',2), + +/* +* jpgraph_theme +*/ +30001 => array("Theme::%s() is not defined. \nPlease make %s(\$graph) function in your theme classs.",2), + + ); ?> diff --git a/src/classes/jpgraph/lang/en.inc.php b/src/classes/jpgraph/lang/en.inc.php index 3d0961d..101e8bd 100644 --- a/src/classes/jpgraph/lang/en.inc.php +++ b/src/classes/jpgraph/lang/en.inc.php @@ -5,7 +5,7 @@ // Created: 2006-01-25 // Ver: $Id: en.inc.php 1886 2009-10-01 23:30:16Z ljp $ // -// Copyright (c) Aditus Consulting. All rights reserved. +// Copyright (c) Asial Corporation. All rights reserved. //======================================================================== */ @@ -187,6 +187,7 @@ HTTP headers have already been sent.
Caused by output from file %s at 15009 => array('Illegal pie plot. Sum of all data is zero for Pie Plot',0), 15010 => array('Sum of all data is 0 for Pie.',0), 15011 => array('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.',0), +15012 => array('PiePlot::SetTheme() is no longer supported. Use PieGraph::SetTheme()',0), /* ** jpgraph_plotband @@ -404,6 +405,8 @@ HTTP headers have already been sent.
Caused by output from file %s at 25130 => array('Too small plot area. (%d x %d). With the given image size and margins there is to little space left for the plot. Increase the plot size or reduce the margins.',2), 25131 => array('StrokeBoxedText2() only supports TTF fonts and not built-in bitmap fonts.',0), +25132 => array('Undefined property %s.',1), +25133 => array('Use Graph::SetTheme() after Graph::SetScale().',0), /* ** jpgraph_led @@ -531,6 +534,12 @@ HTTP headers have already been sent.
Caused by output from file %s at 29209 => array('CSIM Target matrix must be the same size as the data matrix (csim=%d x %d, data=%d x %d)',4), 29210 => array('CSIM Target for matrix labels does not match the number of labels (csim=%d, labels=%d)',2), + +/* +* jpgraph_theme +*/ +30001 => array("Theme::%s() is not defined. \nPlease make %s(\$graph) function in your theme classs.",2), + ); ?> diff --git a/src/classes/jpgraph/lang/prod.inc.php b/src/classes/jpgraph/lang/prod.inc.php index 8b37647..c34c2b3 100644 --- a/src/classes/jpgraph/lang/prod.inc.php +++ b/src/classes/jpgraph/lang/prod.inc.php @@ -6,7 +6,7 @@ // Created: 2006-02-18 // Ver: $Id: prod.inc.php 1886 2009-10-01 23:30:16Z ljp $ // -// Copyright (c) Aditus Consulting. All rights reserved. +// Copyright (c) Asial Corporation. All rights reserved. //======================================================================== */ @@ -120,6 +120,7 @@ HTTP headers have already been sent.
Caused by output from file %s at 15009 => array(DEFAULT_ERROR_MESSAGE.'15009',0), 15010 => array(DEFAULT_ERROR_MESSAGE.'15010',0), 15011 => array(DEFAULT_ERROR_MESSAGE.'15011',0), +15012 => array(DEFAULT_ERROR_MESSAGE.'15012',0), 16001 => array(DEFAULT_ERROR_MESSAGE.'16001',0), 16002 => array(DEFAULT_ERROR_MESSAGE.'16002',0), 16003 => array(DEFAULT_ERROR_MESSAGE.'16003',0), @@ -279,6 +280,8 @@ HTTP headers have already been sent.
Caused by output from file %s at 25129 => array(DEFAULT_ERROR_MESSAGE.'25129',0), 25130 => array(DEFAULT_ERROR_MESSAGE.'25130',0), 25131 => array(DEFAULT_ERROR_MESSAGE.'25131',0), +25132 => array(DEFAULT_ERROR_MESSAGE.'25132',0), +25133 => array(DEFAULT_ERROR_MESSAGE.'25133',0), 25500 => array(DEFAULT_ERROR_MESSAGE.'25500',0), 24003 => array(DEFAULT_ERROR_MESSAGE.'24003',0), 24004 => array(DEFAULT_ERROR_MESSAGE.'24004',0), diff --git a/src/classes/jpgraph/themes/AquaTheme.class.php b/src/classes/jpgraph/themes/AquaTheme.class.php new file mode 100644 index 0000000..751b420 --- /dev/null +++ b/src/classes/jpgraph/themes/AquaTheme.class.php @@ -0,0 +1,202 @@ +img; + $height = $img->height; + $graph->SetMargin($img->left_margin, $img->right_margin, $img->top_margin, $height * 0.25); + */ + $graph->SetFrame(false); + $graph->SetMarginColor('white'); + $graph->SetBackgroundGradient($this->background_color, '#FFFFFF', GRAD_HOR, BGRAD_PLOT); + + // legend + $graph->legend->SetFrameWeight(0); + $graph->legend->Pos(0.5, 0.85, 'center', 'top'); + $graph->legend->SetFillColor('white'); + $graph->legend->SetLayout(LEGEND_HOR); + $graph->legend->SetColumns(3); + $graph->legend->SetShadow(false); + $graph->legend->SetMarkAbsSize(5); + + // xaxis + $graph->xaxis->title->SetColor($this->font_color); + $graph->xaxis->SetColor($this->axis_color, $this->font_color); + $graph->xaxis->SetTickSide(SIDE_BOTTOM); + $graph->xaxis->SetLabelMargin(10); + + // yaxis + $graph->yaxis->title->SetColor($this->font_color); + $graph->yaxis->SetColor($this->axis_color, $this->font_color); + $graph->yaxis->SetTickSide(SIDE_LEFT); + $graph->yaxis->SetLabelMargin(8); + $graph->yaxis->HideLine(); + $graph->yaxis->HideTicks(); + $graph->xaxis->SetTitleMargin(15); + + // grid + $graph->ygrid->SetColor($this->grid_color); + $graph->ygrid->SetLineStyle('dotted'); + + + // font + $graph->title->SetColor($this->font_color); + $graph->subtitle->SetColor($this->font_color); + $graph->subsubtitle->SetColor($this->font_color); + +// $graph->img->SetAntiAliasing(); + } + + + function SetupPieGraph($graph) { + + // graph + $graph->SetFrame(false); + + // legend + $graph->legend->SetFillColor('white'); + + $graph->legend->SetFrameWeight(0); + $graph->legend->Pos(0.5, 0.80, 'center', 'top'); + $graph->legend->SetLayout(LEGEND_HOR); + $graph->legend->SetColumns(4); + + $graph->legend->SetShadow(false); + $graph->legend->SetMarkAbsSize(5); + + // title + $graph->title->SetColor($this->font_color); + $graph->subtitle->SetColor($this->font_color); + $graph->subsubtitle->SetColor($this->font_color); + + $graph->SetAntiAliasing(); + } + + + function PreStrokeApply($graph) { + if ($graph->legend->HasItems()) { + $img = $graph->img; + $height = $img->height; + $graph->SetMargin( + $img->raw_left_margin, + $img->raw_right_margin, + $img->raw_top_margin, + $height * 0.25 + ); + } + } + + function ApplyPlot($plot) { + + switch (get_class($plot)) + { + case 'GroupBarPlot': + { + foreach ($plot->plots as $_plot) { + $this->ApplyPlot($_plot); + } + break; + } + + case 'AccBarPlot': + { + foreach ($plot->plots as $_plot) { + $this->ApplyPlot($_plot); + } + break; + } + + case 'BarPlot': + { + $plot->Clear(); + + $color = $this->GetNextColor(); + $plot->SetColor($color); + $plot->SetFillColor($color); + //$plot->SetShadow(); + break; + } + + case 'LinePlot': + { + $plot->Clear(); + $plot->SetColor($this->GetNextColor()); + $plot->SetWeight(2); +// $plot->SetBarCenter(); + break; + } + + case 'PiePlot': + { + $plot->SetCenter(0.5, 0.45); + $plot->ShowBorder(false); + $plot->SetSliceColors($this->GetThemeColors()); + break; + } + + case 'PiePlot3D': + { + $plot->SetSliceColors($this->GetThemeColors()); + break; + } + + default: + { + } + } + } +} + + +?> diff --git a/src/classes/jpgraph/themes/GreenTheme.class.php b/src/classes/jpgraph/themes/GreenTheme.class.php new file mode 100644 index 0000000..a61fbd8 --- /dev/null +++ b/src/classes/jpgraph/themes/GreenTheme.class.php @@ -0,0 +1,178 @@ +img; + $height = $img->height; + $graph->SetMargin($img->left_margin, $img->right_margin, $img->top_margin, $height * 0.25); + */ + $graph->SetFrame(false); + $graph->SetMarginColor('white'); + $graph->SetBackgroundGradient($this->background_color, '#FFFFFF', GRAD_HOR, BGRAD_PLOT); + + // legend + $graph->legend->SetFrameWeight(0); + $graph->legend->Pos(0.5, 0.85, 'center', 'top'); + $graph->legend->SetFillColor('white'); + $graph->legend->SetLayout(LEGEND_HOR); + $graph->legend->SetColumns(3); + $graph->legend->SetShadow(false); + $graph->legend->SetMarkAbsSize(5); + + // xaxis + $graph->xaxis->title->SetColor($this->font_color); + $graph->xaxis->SetColor($this->axis_color, $this->font_color); + $graph->xaxis->SetTickSide(SIDE_BOTTOM); + $graph->xaxis->SetLabelMargin(10); + + // yaxis + $graph->yaxis->title->SetColor($this->font_color); + $graph->yaxis->SetColor($this->axis_color, $this->font_color); + $graph->yaxis->SetTickSide(SIDE_LEFT); + $graph->yaxis->SetLabelMargin(8); + $graph->yaxis->HideLine(); + $graph->yaxis->HideTicks(); + $graph->xaxis->SetTitleMargin(15); + + // grid + $graph->ygrid->SetColor($this->grid_color); + $graph->ygrid->SetLineStyle('dotted'); + + + // font + $graph->title->SetColor($this->font_color); + $graph->subtitle->SetColor($this->font_color); + $graph->subsubtitle->SetColor($this->font_color); + +// $graph->img->SetAntiAliasing(); + } + + + function SetupPieGraph($graph) { + + // graph + $graph->SetFrame(false); + + // legend + $graph->legend->SetFillColor('white'); + /* + $graph->legend->SetFrameWeight(0); + $graph->legend->Pos(0.5, 0.85, 'center', 'top'); + $graph->legend->SetLayout(LEGEND_HOR); + $graph->legend->SetColumns(3); + */ + $graph->legend->SetShadow(false); + $graph->legend->SetMarkAbsSize(5); + + // title + $graph->title->SetColor($this->font_color); + $graph->subtitle->SetColor($this->font_color); + $graph->subsubtitle->SetColor($this->font_color); + + $graph->SetAntiAliasing(); + } + + + function PreStrokeApply($graph) { + if ($graph->legend->HasItems()) { + $img = $graph->img; + $height = $img->height; + $graph->SetMargin($img->left_margin, $img->right_margin, $img->top_margin, $height * 0.25); + } + } + + function ApplyPlot($plot) { + + switch (get_class($plot)) + { + case 'GroupBarPlot': + { + foreach ($plot->plots as $_plot) { + $this->ApplyPlot($_plot); + } + break; + } + + case 'AccBarPlot': + { + foreach ($plot->plots as $_plot) { + $this->ApplyPlot($_plot); + } + break; + } + + case 'BarPlot': + { + $plot->Clear(); + + $color = $this->GetNextColor(); + $plot->SetColor($color); + $plot->SetFillColor($color); + $plot->SetShadow('red', 3, 4, false); + break; + } + + case 'LinePlot': + { + $plot->Clear(); + + $plot->SetColor($this->GetNextColor().'@0.4'); + $plot->SetWeight(2); + break; + } + + case 'PiePlot': + { + $plot->ShowBorder(false); + $plot->SetSliceColors($this->GetThemeColors()); + break; + } + + case 'PiePlot3D': + { + $plot->SetSliceColors($this->GetThemeColors()); + break; + } + + default: + { + } + } + } +} + + +?> diff --git a/src/classes/jpgraph/themes/OceanTheme.class.php b/src/classes/jpgraph/themes/OceanTheme.class.php new file mode 100644 index 0000000..b275036 --- /dev/null +++ b/src/classes/jpgraph/themes/OceanTheme.class.php @@ -0,0 +1,180 @@ +img; + $height = $img->height; + $graph->SetMargin($img->left_margin, $img->right_margin, $img->top_margin, $height * 0.25); + */ + $graph->SetFrame(false); + $graph->SetMarginColor('white'); + $graph->SetBackgroundGradient($this->background_color, '#FFFFFF', GRAD_HOR, BGRAD_PLOT); + + // legend + $graph->legend->SetFrameWeight(0); + $graph->legend->Pos(0.5, 0.85, 'center', 'top'); + $graph->legend->SetFillColor('white'); + $graph->legend->SetLayout(LEGEND_HOR); + $graph->legend->SetColumns(3); + $graph->legend->SetShadow(false); + $graph->legend->SetMarkAbsSize(5); + + // xaxis + $graph->xaxis->title->SetColor($this->font_color); + $graph->xaxis->SetColor($this->axis_color, $this->font_color); + $graph->xaxis->SetTickSide(SIDE_BOTTOM); + $graph->xaxis->SetLabelMargin(10); + + // yaxis + $graph->yaxis->title->SetColor($this->font_color); + $graph->yaxis->SetColor($this->axis_color, $this->font_color); + $graph->yaxis->SetTickSide(SIDE_LEFT); + $graph->yaxis->SetLabelMargin(8); + $graph->yaxis->HideLine(); + $graph->yaxis->HideTicks(); + $graph->xaxis->SetTitleMargin(15); + + // grid + $graph->ygrid->SetColor($this->grid_color); + $graph->ygrid->SetLineStyle('dotted'); + + + // font + $graph->title->SetColor($this->font_color); + $graph->subtitle->SetColor($this->font_color); + $graph->subsubtitle->SetColor($this->font_color); + +// $graph->img->SetAntiAliasing(); + } + + + function SetupPieGraph($graph) { + + // graph + $graph->SetFrame(false); + + // legend + $graph->legend->SetFillColor('white'); + /* + $graph->legend->SetFrameWeight(0); + $graph->legend->Pos(0.5, 0.85, 'center', 'top'); + $graph->legend->SetLayout(LEGEND_HOR); + $graph->legend->SetColumns(3); + */ + $graph->legend->SetShadow(false); + $graph->legend->SetMarkAbsSize(5); + + // title + $graph->title->SetColor($this->font_color); + $graph->subtitle->SetColor($this->font_color); + $graph->subsubtitle->SetColor($this->font_color); + + $graph->SetAntiAliasing(); + } + + + function PreStrokeApply($graph) { + if ($graph->legend->HasItems()) { + $img = $graph->img; + $height = $img->height; + $graph->SetMargin($img->left_margin, $img->right_margin, $img->top_margin, $height * 0.25); + } + } + + function ApplyPlot($plot) { + + switch (get_class($plot)) + { + case 'GroupBarPlot': + { + foreach ($plot->plots as $_plot) { + $this->ApplyPlot($_plot); + } + break; + } + + case 'AccBarPlot': + { + foreach ($plot->plots as $_plot) { + $this->ApplyPlot($_plot); + } + break; + } + + case 'BarPlot': + { + $plot->Clear(); + + $color = $this->GetNextColor(); + $plot->SetColor($color); + $plot->SetFillColor($color); + $plot->SetShadow('red', 3, 4, false); + break; + } + + case 'LinePlot': + { + $plot->Clear(); + + $plot->SetColor($this->GetNextColor()); + $plot->SetWeight(2); + break; + } + + case 'PiePlot': + { + $plot->ShowBorder(false); + $plot->SetSliceColors($this->GetThemeColors()); + break; + } + + case 'PiePlot3D': + { + $plot->SetSliceColors($this->GetThemeColors()); + break; + } + + default: + { + } + } + } +} + + +?> diff --git a/src/classes/jpgraph/themes/OrangeTheme.class.php b/src/classes/jpgraph/themes/OrangeTheme.class.php new file mode 100644 index 0000000..ea26dad --- /dev/null +++ b/src/classes/jpgraph/themes/OrangeTheme.class.php @@ -0,0 +1,180 @@ +img; + $height = $img->height; + $graph->SetMargin($img->left_margin, $img->right_margin, $img->top_margin, $height * 0.25); + */ + $graph->SetFrame(false); + $graph->SetMarginColor('white'); + $graph->SetBackgroundGradient($this->background_color, '#FFFFFF', GRAD_HOR, BGRAD_PLOT); + + // legend + $graph->legend->SetFrameWeight(0); + $graph->legend->Pos(0.5, 0.85, 'center', 'top'); + $graph->legend->SetFillColor('white'); + $graph->legend->SetLayout(LEGEND_HOR); + $graph->legend->SetColumns(3); + $graph->legend->SetShadow(false); + $graph->legend->SetMarkAbsSize(5); + + // xaxis + $graph->xaxis->title->SetColor($this->font_color); + $graph->xaxis->SetColor($this->axis_color, $this->font_color); + $graph->xaxis->SetTickSide(SIDE_BOTTOM); + $graph->xaxis->SetLabelMargin(10); + + // yaxis + $graph->yaxis->title->SetColor($this->font_color); + $graph->yaxis->SetColor($this->axis_color, $this->font_color); + $graph->yaxis->SetTickSide(SIDE_LEFT); + $graph->yaxis->SetLabelMargin(8); + $graph->yaxis->HideLine(); + $graph->yaxis->HideTicks(); + $graph->xaxis->SetTitleMargin(15); + + // grid + $graph->ygrid->SetColor($this->grid_color); + $graph->ygrid->SetLineStyle('dotted'); + + + // font + $graph->title->SetColor($this->font_color); + $graph->subtitle->SetColor($this->font_color); + $graph->subsubtitle->SetColor($this->font_color); + +// $graph->img->SetAntiAliasing(); + } + + + function SetupPieGraph($graph) { + + // graph + $graph->SetFrame(false); + + // legend + $graph->legend->SetFillColor('white'); + /* + $graph->legend->SetFrameWeight(0); + $graph->legend->Pos(0.5, 0.85, 'center', 'top'); + $graph->legend->SetLayout(LEGEND_HOR); + $graph->legend->SetColumns(3); + */ + $graph->legend->SetShadow(false); + $graph->legend->SetMarkAbsSize(5); + + // title + $graph->title->SetColor($this->font_color); + $graph->subtitle->SetColor($this->font_color); + $graph->subsubtitle->SetColor($this->font_color); + + $graph->SetAntiAliasing(); + } + + + function PreStrokeApply($graph) { + if ($graph->legend->HasItems()) { + $img = $graph->img; + $height = $img->height; + $graph->SetMargin($img->left_margin, $img->right_margin, $img->top_margin, $height * 0.25); + } + } + + function ApplyPlot($plot) { + + switch (get_class($plot)) + { + case 'GroupBarPlot': + { + foreach ($plot->plots as $_plot) { + $this->ApplyPlot($_plot); + } + break; + } + + case 'AccBarPlot': + { + foreach ($plot->plots as $_plot) { + $this->ApplyPlot($_plot); + } + break; + } + + case 'BarPlot': + { + $plot->Clear(); + + $color = $this->GetNextColor(); + $plot->SetColor($color); + $plot->SetFillColor($color); + $plot->SetShadow('red', 3, 4, false); + break; + } + + case 'LinePlot': + { + $plot->Clear(); + + $plot->SetColor($this->GetNextColor().'@0.4'); + $plot->SetWeight(2); + break; + } + + case 'PiePlot': + { + $plot->ShowBorder(false); + $plot->SetSliceColors($this->GetThemeColors()); + break; + } + + case 'PiePlot3D': + { + $plot->SetSliceColors($this->GetThemeColors()); + break; + } + + default: + { + } + } + } +} + + +?> diff --git a/src/classes/jpgraph/themes/PastelTheme.class.php b/src/classes/jpgraph/themes/PastelTheme.class.php new file mode 100644 index 0000000..d3f1ddb --- /dev/null +++ b/src/classes/jpgraph/themes/PastelTheme.class.php @@ -0,0 +1,175 @@ +img; + $height = $img->height; + $graph->SetMargin($img->left_margin, $img->right_margin, $img->top_margin, $height * 0.25); + */ + $graph->SetFrame(false); + $graph->SetMarginColor('white'); + $graph->SetBackgroundGradient($this->background_color, '#FFFFFF', GRAD_HOR, BGRAD_PLOT); + + // legend + $graph->legend->SetFrameWeight(0); + $graph->legend->Pos(0.5, 0.85, 'center', 'top'); + $graph->legend->SetFillColor('white'); + $graph->legend->SetLayout(LEGEND_HOR); + $graph->legend->SetColumns(3); + $graph->legend->SetShadow(false); + $graph->legend->SetMarkAbsSize(5); + + // xaxis + $graph->xaxis->title->SetColor($this->font_color); + $graph->xaxis->SetColor($this->axis_color, $this->font_color); + $graph->xaxis->SetTickSide(SIDE_BOTTOM); + $graph->xaxis->SetLabelMargin(10); + + // yaxis + $graph->yaxis->title->SetColor($this->font_color); + $graph->yaxis->SetColor($this->axis_color, $this->font_color); + $graph->yaxis->SetTickSide(SIDE_LEFT); + $graph->yaxis->SetLabelMargin(8); + $graph->yaxis->HideLine(); + $graph->yaxis->HideTicks(); + $graph->xaxis->SetTitleMargin(15); + + // grid + $graph->ygrid->SetColor($this->grid_color); + $graph->ygrid->SetLineStyle('dotted'); + + + // font + $graph->title->SetColor($this->font_color); + $graph->subtitle->SetColor($this->font_color); + $graph->subsubtitle->SetColor($this->font_color); + +// $graph->img->SetAntiAliasing(); + } + + + function SetupPieGraph($graph) { + + // graph + $graph->SetFrame(false); + + // legend + $graph->legend->SetFillColor('white'); + + $graph->legend->SetFrameWeight(0); + $graph->legend->Pos(0.5, 0.80, 'center', 'top'); + $graph->legend->SetLayout(LEGEND_HOR); + $graph->legend->SetColumns(4); + + $graph->legend->SetShadow(false); + $graph->legend->SetMarkAbsSize(5); + + // title + $graph->title->SetColor($this->font_color); + $graph->subtitle->SetColor($this->font_color); + $graph->subsubtitle->SetColor($this->font_color); + + $graph->SetAntiAliasing(); + } + + + function PreStrokeApply($graph) { + if ($graph->legend->HasItems()) { + $img = $graph->img; + $height = $img->height; + $graph->SetMargin($img->left_margin, $img->right_margin, $img->top_margin, $height * 0.25); + } + } + + function ApplyPlot($plot) { + + switch (get_class($plot)) + { + case 'GroupBarPlot': + { + foreach ($plot->plots as $_plot) { + $this->ApplyPlot($_plot); + } + break; + } + + case 'AccBarPlot': + { + foreach ($plot->plots as $_plot) { + $this->ApplyPlot($_plot); + } + break; + } + + case 'BarPlot': + { + $plot->Clear(); + + $color = $this->GetNextColor(); + $plot->SetColor($color); + $plot->SetFillColor($color); + $plot->SetShadow('red', 3, 4, false); + break; + } + + case 'LinePlot': + { + $plot->Clear(); + $plot->SetColor($this->GetNextColor().'@0.4'); + $plot->SetWeight(2); +// $plot->SetBarCenter(); + break; + } + + case 'PiePlot': + { + $plot->SetCenter(0.5, 0.45); + $plot->ShowBorder(false); + $plot->SetSliceColors($this->GetThemeColors()); + break; + } + + case 'PiePlot3D': + { + $plot->SetSliceColors($this->GetThemeColors()); + break; + } + + default: + { + } + } + } +} + + +?> diff --git a/src/classes/jpgraph/themes/RoseTheme.class.php b/src/classes/jpgraph/themes/RoseTheme.class.php new file mode 100644 index 0000000..5a14630 --- /dev/null +++ b/src/classes/jpgraph/themes/RoseTheme.class.php @@ -0,0 +1,180 @@ +img; + $height = $img->height; + $graph->SetMargin($img->left_margin, $img->right_margin, $img->top_margin, $height * 0.25); + */ + $graph->SetFrame(false); + $graph->SetMarginColor('white'); + $graph->SetBackgroundGradient($this->background_color, '#FFFFFF', GRAD_HOR, BGRAD_PLOT); + + // legend + $graph->legend->SetFrameWeight(0); + $graph->legend->Pos(0.5, 0.85, 'center', 'top'); + $graph->legend->SetFillColor('white'); + $graph->legend->SetLayout(LEGEND_HOR); + $graph->legend->SetColumns(3); + $graph->legend->SetShadow(false); + $graph->legend->SetMarkAbsSize(5); + + // xaxis + $graph->xaxis->title->SetColor($this->font_color); + $graph->xaxis->SetColor($this->axis_color, $this->font_color); + $graph->xaxis->SetTickSide(SIDE_BOTTOM); + $graph->xaxis->SetLabelMargin(10); + + // yaxis + $graph->yaxis->title->SetColor($this->font_color); + $graph->yaxis->SetColor($this->axis_color, $this->font_color); + $graph->yaxis->SetTickSide(SIDE_LEFT); + $graph->yaxis->SetLabelMargin(8); + $graph->yaxis->HideLine(); + $graph->yaxis->HideTicks(); + $graph->xaxis->SetTitleMargin(15); + + // grid + $graph->ygrid->SetColor($this->grid_color); + $graph->ygrid->SetLineStyle('dotted'); + + + // font + $graph->title->SetColor($this->font_color); + $graph->subtitle->SetColor($this->font_color); + $graph->subsubtitle->SetColor($this->font_color); + +// $graph->img->SetAntiAliasing(); + } + + + function SetupPieGraph($graph) { + + // graph + $graph->SetFrame(false); + + // legend + $graph->legend->SetFillColor('white'); + /* + $graph->legend->SetFrameWeight(0); + $graph->legend->Pos(0.5, 0.85, 'center', 'top'); + $graph->legend->SetLayout(LEGEND_HOR); + $graph->legend->SetColumns(3); + */ + $graph->legend->SetShadow(false); + $graph->legend->SetMarkAbsSize(5); + + // title + $graph->title->SetColor($this->font_color); + $graph->subtitle->SetColor($this->font_color); + $graph->subsubtitle->SetColor($this->font_color); + + $graph->SetAntiAliasing(); + } + + + function PreStrokeApply($graph) { + if ($graph->legend->HasItems()) { + $img = $graph->img; + $height = $img->height; + $graph->SetMargin($img->left_margin, $img->right_margin, $img->top_margin, $height * 0.25); + } + } + + function ApplyPlot($plot) { + + switch (get_class($plot)) + { + case 'GroupBarPlot': + { + foreach ($plot->plots as $_plot) { + $this->ApplyPlot($_plot); + } + break; + } + + case 'AccBarPlot': + { + foreach ($plot->plots as $_plot) { + $this->ApplyPlot($_plot); + } + break; + } + + case 'BarPlot': + { + $plot->Clear(); + + $color = $this->GetNextColor(); + $plot->SetColor($color); + $plot->SetFillColor($color); + $plot->SetShadow('red', 3, 4, false); + break; + } + + case 'LinePlot': + { + $plot->Clear(); + + $plot->SetColor($this->GetNextColor().'@0.4'); + $plot->SetWeight(2); + break; + } + + case 'PiePlot': + { + $plot->ShowBorder(false); + $plot->SetSliceColors($this->GetThemeColors()); + break; + } + + case 'PiePlot3D': + { + $plot->SetSliceColors($this->GetThemeColors()); + break; + } + + default: + { + } + } + } +} + + +?> diff --git a/src/classes/jpgraph/themes/SoftyTheme.class.php b/src/classes/jpgraph/themes/SoftyTheme.class.php new file mode 100644 index 0000000..222cf85 --- /dev/null +++ b/src/classes/jpgraph/themes/SoftyTheme.class.php @@ -0,0 +1,209 @@ +SetFrame(false); + $graph->SetMarginColor('white'); + + // legend + $graph->legend->SetFrameWeight(0); + $graph->legend->Pos(0.5, 0.85, 'center', 'top'); + $graph->legend->SetFillColor('white'); + $graph->legend->SetLayout(LEGEND_HOR); + $graph->legend->SetColumns(3); + $graph->legend->SetShadow(false); + $graph->legend->SetMarkAbsSize(5); + + // xaxis + $graph->xaxis->title->SetColor($this->font_color); + $graph->xaxis->SetColor($this->axis_color, $this->font_color); + $graph->xaxis->SetTickSide(SIDE_BOTTOM); + $graph->xaxis->SetLabelMargin(10); + + // yaxis + $graph->yaxis->title->SetColor($this->font_color); + $graph->yaxis->SetColor($this->axis_color, $this->font_color); + $graph->yaxis->SetTickSide(SIDE_LEFT); + $graph->yaxis->SetLabelMargin(8); + $graph->yaxis->HideLine(); + $graph->yaxis->HideTicks(); + $graph->xaxis->SetTitleMargin(15); + + // y2~ + if (isset($graph->y2axis)) { + $graph->y2axis->title->SetColor($this->font_color); + $graph->y2axis->SetColor($this->axis_color, $this->font_color); + $graph->y2axis->SetTickSide(SIDE_LEFT); + $graph->y2axis->SetLabelMargin(8); + $graph->y2axis->HideLine(); + $graph->y2axis->HideTicks(); + } + + // yn + if (isset($graph->y2axis)) { + foreach ($graph->ynaxis as $axis) { + $axis->title->SetColor($this->font_color); + $axis->SetColor($this->axis_color, $this->font_color); + $axis->SetTickSide(SIDE_LEFT); + $axis->SetLabelMargin(8); + $axis->HideLine(); + $axis->HideTicks(); + } + } + + // grid + $graph->ygrid->SetColor($this->grid_color); + $graph->ygrid->SetLineStyle('dotted'); + $graph->ygrid->SetFill(true, '#FFFFFF', $this->background_color); + $graph->xgrid->Show(); + $graph->xgrid->SetColor($this->grid_color); + $graph->xgrid->SetLineStyle('dotted'); + + + // font + $graph->title->SetColor($this->font_color); + $graph->subtitle->SetColor($this->font_color); + $graph->subsubtitle->SetColor($this->font_color); + +// $graph->img->SetAntiAliasing(); + } + + + function SetupPieGraph($graph) { + + // graph + $graph->SetFrame(false); + + // title + $graph->title->SetColor($this->font_color); + $graph->subtitle->SetColor($this->font_color); + $graph->subsubtitle->SetColor($this->font_color); + + $graph->SetAntiAliasing(); + } + + + function PreStrokeApply($graph) { + if ($graph->legend->HasItems()) { + $img = $graph->img; + $graph->SetMargin($img->left_margin, $img->right_margin, $img->top_margin, $img->height * 0.25); +// $graph->SetMargin(200, $img->right_margin, $img->top_margin, $height * 0.25); + } + } + + function ApplyPlot($plot) { + + switch (get_class($plot)) + { + case 'BarPlot': + { + $plot->Clear(); + + $color = $this->GetNextColor(); + $plot->SetColor($color); + $plot->SetFillColor($color); + $plot->SetShadow('red', 3, 4, false); + $plot->value->SetAlign('center', 'center'); + break; + } + + case 'LinePlot': + { + $plot->Clear(); + + $plot->SetColor($this->GetNextColor()); + $plot->SetWeight(2); +// $plot->SetBarCenter(); + break; + } + + case 'PiePlot': + { + $plot->ShowBorder(false); + $plot->SetSliceColors($this->GetThemeColors()); + break; + } + + + case 'GroupBarPlot': + { + foreach ($plot->plots as $_plot) { + $this->ApplyPlot($_plot); + } + break; + } + + case 'AccBarPlot': + { + $plot->value->SetAlign('center', 'center'); + foreach ($plot->plots as $_plot) { + $this->ApplyPlot($_plot); + $_plot->SetValuePos('center'); + } + break; + } + + case 'ScatterPlot': + { + break; + } + + + case 'PiePlot3D': + { + $plot->SetSliceColors($this->GetThemeColors()); + break; + } + + default: + { + } + } + } +} + + +?> diff --git a/src/classes/jpgraph/themes/UniversalTheme.class.php b/src/classes/jpgraph/themes/UniversalTheme.class.php new file mode 100644 index 0000000..44b57a6 --- /dev/null +++ b/src/classes/jpgraph/themes/UniversalTheme.class.php @@ -0,0 +1,188 @@ +img; + $height = $img->height; + $graph->SetMargin($img->left_margin, $img->right_margin, $img->top_margin, $height * 0.25); + */ + $graph->SetFrame(false); + $graph->SetMarginColor('white'); + $graph->SetBox(true, '#DADADA'); +// $graph->SetBackgroundGradient($this->background_color, '#FFFFFF', GRAD_HOR, BGRAD_PLOT); + + // legend + $graph->legend->SetFrameWeight(0); + $graph->legend->Pos(0.5, 0.85, 'center', 'top'); + $graph->legend->SetFillColor('white'); + $graph->legend->SetLayout(LEGEND_HOR); + $graph->legend->SetColumns(3); + $graph->legend->SetShadow(false); + $graph->legend->SetMarkAbsSize(5); + + // xaxis + $graph->xaxis->title->SetColor($this->font_color); + $graph->xaxis->SetColor($this->axis_color, $this->font_color); + $graph->xaxis->SetTickSide(SIDE_BOTTOM); + $graph->xaxis->SetLabelMargin(10); + $graph->xaxis->HideTicks(); + $graph->xaxis->SetTitleMargin(15); + //$graph->xaxis->SetLabelMargin(30); + + // yaxis + $graph->yaxis->title->SetColor($this->font_color); + $graph->yaxis->SetColor($this->axis_color, $this->font_color); + $graph->yaxis->SetTickSide(SIDE_LEFT); + $graph->yaxis->SetLabelMargin(8); +// $graph->yaxis->SetTickPositions(array(50, 100, 150)); +// $graph->yaxis->HideLine(); + $graph->yaxis->HideTicks(); + + // grid + $graph->ygrid->SetColor($this->grid_color); + $graph->ygrid->SetFill(true, '#FFFFFF', $this->background_color); + // $graph->ygrid->SetLineStyle('dotted'); + + + // font + $graph->title->SetColor($this->font_color); + $graph->subtitle->SetColor($this->font_color); + $graph->subsubtitle->SetColor($this->font_color); + + $graph->img->SetAntiAliasing(); + } + + + function SetupPieGraph($graph) { + + // graph + $graph->SetFrame(false); + + // legend + $graph->legend->SetFillColor('white'); + + $graph->legend->SetFrameWeight(0); + $graph->legend->Pos(0.5, 0.80, 'center', 'top'); + $graph->legend->SetLayout(LEGEND_HOR); + $graph->legend->SetColumns(4); + + $graph->legend->SetShadow(false); + $graph->legend->SetMarkAbsSize(5); + + // title + $graph->title->SetColor($this->font_color); + $graph->subtitle->SetColor($this->font_color); + $graph->subsubtitle->SetColor($this->font_color); + + $graph->SetAntiAliasing(); + } + + + function PreStrokeApply($graph) { + if ($graph->legend->HasItems()) { + $img = $graph->img; + $height = $img->height; + $graph->SetMargin( + $img->raw_left_margin, + $img->raw_right_margin, + $img->raw_top_margin, + $height * 0.25 + ); + } + } + + function ApplyPlot($plot) { + + switch (get_class($plot)) + { + case 'GroupBarPlot': + { + foreach ($plot->plots as $_plot) { + $this->ApplyPlot($_plot); + } + break; + } + + case 'AccBarPlot': + { + foreach ($plot->plots as $_plot) { + $this->ApplyPlot($_plot); + } + break; + } + + case 'BarPlot': + { + $plot->Clear(); + + $color = $this->GetNextColor(); + $plot->SetColor($color); + $plot->SetFillColor($color); + $plot->SetShadow('red', 3, 4, false); + break; + } + + case 'LinePlot': + { + $plot->Clear(); + $plot->SetColor($this->GetNextColor().'@0.4'); + $plot->SetWeight(2); + break; + } + + case 'PiePlot': + { + $plot->SetCenter(0.5, 0.45); + $plot->ShowBorder(false); + $plot->SetSliceColors($this->GetThemeColors()); + break; + } + + case 'PiePlot3D': + { + $plot->SetSliceColors($this->GetThemeColors()); + break; + } + + default: + { + } + } + } +} + + +?> diff --git a/src/classes/jpgraph/themes/VividTheme.class.php b/src/classes/jpgraph/themes/VividTheme.class.php new file mode 100644 index 0000000..38a7709 --- /dev/null +++ b/src/classes/jpgraph/themes/VividTheme.class.php @@ -0,0 +1,175 @@ +img; + $height = $img->height; + $graph->SetMargin($img->left_margin, $img->right_margin, $img->top_margin, $height * 0.25); + */ + $graph->SetFrame(false); + $graph->SetMarginColor('white'); + $graph->SetBackgroundGradient($this->background_color, '#FFFFFF', GRAD_HOR, BGRAD_PLOT); + + // legend + $graph->legend->SetFrameWeight(0); + $graph->legend->Pos(0.5, 0.85, 'center', 'top'); + $graph->legend->SetFillColor('white'); + $graph->legend->SetLayout(LEGEND_HOR); + $graph->legend->SetColumns(3); + $graph->legend->SetShadow(false); + $graph->legend->SetMarkAbsSize(5); + + // xaxis + $graph->xaxis->title->SetColor($this->font_color); + $graph->xaxis->SetColor($this->axis_color, $this->font_color); + $graph->xaxis->SetTickSide(SIDE_BOTTOM); + $graph->xaxis->SetLabelMargin(10); + + // yaxis + $graph->yaxis->title->SetColor($this->font_color); + $graph->yaxis->SetColor($this->axis_color, $this->font_color); + $graph->yaxis->SetTickSide(SIDE_LEFT); + $graph->yaxis->SetLabelMargin(8); + $graph->yaxis->HideLine(); + $graph->yaxis->HideTicks(); + $graph->xaxis->SetTitleMargin(15); + + // grid + $graph->ygrid->SetColor($this->grid_color); + $graph->ygrid->SetLineStyle('dotted'); + + + // font + $graph->title->SetColor($this->font_color); + $graph->subtitle->SetColor($this->font_color); + $graph->subsubtitle->SetColor($this->font_color); + +// $graph->img->SetAntiAliasing(); + } + + + function SetupPieGraph($graph) { + + // graph + $graph->SetFrame(false); + + // legend + $graph->legend->SetFillColor('white'); + + $graph->legend->SetFrameWeight(0); + $graph->legend->Pos(0.5, 0.80, 'center', 'top'); + $graph->legend->SetLayout(LEGEND_HOR); + $graph->legend->SetColumns(4); + + $graph->legend->SetShadow(false); + $graph->legend->SetMarkAbsSize(5); + + // title + $graph->title->SetColor($this->font_color); + $graph->subtitle->SetColor($this->font_color); + $graph->subsubtitle->SetColor($this->font_color); + + $graph->SetAntiAliasing(); + } + + + function PreStrokeApply($graph) { + if ($graph->legend->HasItems()) { + $img = $graph->img; + $height = $img->height; + $graph->SetMargin($img->left_margin, $img->right_margin, $img->top_margin, $height * 0.25); + } + } + + function ApplyPlot($plot) { + + switch (get_class($plot)) + { + case 'GroupBarPlot': + { + foreach ($plot->plots as $_plot) { + $this->ApplyPlot($_plot); + } + break; + } + + case 'AccBarPlot': + { + foreach ($plot->plots as $_plot) { + $this->ApplyPlot($_plot); + } + break; + } + + case 'BarPlot': + { + $plot->Clear(); + + $color = $this->GetNextColor(); + $plot->SetColor($color); + $plot->SetFillColor($color); + $plot->SetShadow('red', 3, 4, false); + break; + } + + case 'LinePlot': + { + $plot->Clear(); + $plot->SetColor($this->GetNextColor().'@0.4'); + $plot->SetWeight(2); +// $plot->SetBarCenter(); + break; + } + + case 'PiePlot': + { + $plot->SetCenter(0.5, 0.45); + $plot->ShowBorder(false); + $plot->SetSliceColors($this->GetThemeColors()); + break; + } + + case 'PiePlot3D': + { + $plot->SetSliceColors($this->GetThemeColors()); + break; + } + + default: + { + } + } + } +} + + +?> diff --git a/src/classes/logstreamdb.class.php b/src/classes/logstreamdb.class.php index dc17b41..e2f602f 100644 --- a/src/classes/logstreamdb.class.php +++ b/src/classes/logstreamdb.class.php @@ -64,9 +64,6 @@ class LogStreamDB extends LogStream { private $_myDBQuery = null; // Constructor - public function LogStreamDB($streamConfigObj) { - self::__construct($streamConfigObj); - } public function __construct ($streamConfigObj) { $this->_logStreamConfigObj = $streamConfigObj; @@ -77,6 +74,9 @@ class LogStreamDB extends LogStream { DieWithFriendlyErrorMsg("Error, MYSQL Extensions are not enabled! Function 'mysql_connect' does not exist."); } } + public function LogStreamDB($streamConfigObj) { + self::__construct($streamConfigObj); + } /** * Open and verifies the database conncetion diff --git a/src/classes/logstreamdisk.class.php b/src/classes/logstreamdisk.class.php index 83d93a4..c07cd21 100644 --- a/src/classes/logstreamdisk.class.php +++ b/src/classes/logstreamdisk.class.php @@ -63,12 +63,12 @@ class LogStreamDisk extends LogStream { private $_lastPageUID = -1; // Constructor - public function LogStreamDisk($streamConfigObj) { - self::__construct($streamConfigObj); - } public function __construct ($streamConfigObj) { $this->_logStreamConfigObj = $streamConfigObj; } + public function LogStreamDisk($streamConfigObj) { + self::__construct($streamConfigObj); + } /** * Open the file with read access. diff --git a/src/classes/logstreamlineparsermisc.class.php b/src/classes/logstreamlineparsermisc.class.php index 9298878..b2691e0 100644 --- a/src/classes/logstreamlineparsermisc.class.php +++ b/src/classes/logstreamlineparsermisc.class.php @@ -53,12 +53,12 @@ class LogStreamLineParsermisc extends LogStreamLineParser { // protected $_arrProperties = null; // Constructor - public function LogStreamLineParsermisc() { - self::__construct(); - } public function __construct () { return; // Nothing } + public function LogStreamLineParsermisc() { + self::__construct(); + } /** * ParseLine diff --git a/src/classes/logstreamlineparsersyslog.class.php b/src/classes/logstreamlineparsersyslog.class.php index 550617d..33e1b4f 100644 --- a/src/classes/logstreamlineparsersyslog.class.php +++ b/src/classes/logstreamlineparsersyslog.class.php @@ -52,12 +52,12 @@ class LogStreamLineParsersyslog extends LogStreamLineParser { // protected $_arrProperties = null; // Constructor - public function LogStreamLineParsersyslog() { - self::__construct(); - } public function __construct () { return; // Nothing } + public function LogStreamLineParsersyslog() { + self::__construct(); + } /** * ParseLine diff --git a/src/classes/logstreamlineparsersyslog23.class.php b/src/classes/logstreamlineparsersyslog23.class.php index 4de875a..1c9d559 100644 --- a/src/classes/logstreamlineparsersyslog23.class.php +++ b/src/classes/logstreamlineparsersyslog23.class.php @@ -52,12 +52,12 @@ class LogStreamLineParsersyslog23 extends LogStreamLineParser { // protected $_arrProperties = null; // Constructor - public function LogStreamLineParsersyslog23() { - self::__construct(); - } public function __construct () { return; // Nothing } + public function LogStreamLineParsersyslog23() { + self::__construct(); + } /** * ParseLine diff --git a/src/classes/logstreamlineparsersyslogng.class.php b/src/classes/logstreamlineparsersyslogng.class.php index 766b5ea..77b75f1 100644 --- a/src/classes/logstreamlineparsersyslogng.class.php +++ b/src/classes/logstreamlineparsersyslogng.class.php @@ -73,12 +73,12 @@ class LogStreamLineParsersyslog extends LogStreamLineParser { // protected $_arrProperties = null; // Constructor - public function LogStreamLineParsersyslog() { - self::__construct(); - } public function __construct () { return; // Nothing } + public function LogStreamLineParsersyslog() { + self::__construct(); + } /** * ParseLine diff --git a/src/classes/logstreamlineparserwinsyslog.class.php b/src/classes/logstreamlineparserwinsyslog.class.php index 8d3bf5d..1890f3f 100644 --- a/src/classes/logstreamlineparserwinsyslog.class.php +++ b/src/classes/logstreamlineparserwinsyslog.class.php @@ -52,12 +52,12 @@ class LogStreamLineParserwinsyslog extends LogStreamLineParser { // protected $_arrProperties = null; // Constructor - public function LogStreamLineParserwinsyslog() { - self::__construct(); - } public function __construct () { return; // Nothing } + public function LogStreamLineParserwinsyslog() { + self::__construct(); + } /** * ParseLine diff --git a/src/classes/logstreammongodb.class.php b/src/classes/logstreammongodb.class.php index ba919df..8131712 100644 --- a/src/classes/logstreammongodb.class.php +++ b/src/classes/logstreammongodb.class.php @@ -68,10 +68,6 @@ class LogStreamMongoDB extends LogStream { private $_myMongoQuery = null; // Constructor - public function LogStreamMongoDB($streamConfigObj) { - self::__construct($streamConfigObj); - } - public function __construct ($streamConfigObj) { $this->_logStreamConfigObj = $streamConfigObj; @@ -79,6 +75,9 @@ class LogStreamMongoDB extends LogStream { if ( !function_exists("bson_encode") ) DieWithFriendlyErrorMsg("Error, MongoDB PHP Driver Extensions is not installed! Please see http://www.php.net/manual/en/mongo.installation.php for installation details."); } + public function LogStreamMongoDB($streamConfigObj) { + self::__construct($streamConfigObj); + } /** * Open and verifies the database conncetion diff --git a/src/classes/logstreampdo.class.php b/src/classes/logstreampdo.class.php index b3c19e8..e583f64 100644 --- a/src/classes/logstreampdo.class.php +++ b/src/classes/logstreampdo.class.php @@ -60,10 +60,6 @@ class LogStreamPDO extends LogStream { private $_myDBQuery = null; // Constructor - public function LogStreamPDO($streamConfigObj) { - self::__construct($streamConfigObj); - } - public function __construct ($streamConfigObj) { $this->_logStreamConfigObj = $streamConfigObj; @@ -71,6 +67,9 @@ class LogStreamPDO extends LogStream { if ( extension_loaded('pdo') == 0 ) DieWithFriendlyErrorMsg("Error, PDO Extensions are not enabled or installed! This Source can not operate."); } + public function LogStreamPDO($streamConfigObj) { + self::__construct($streamConfigObj); + } /** * Open and verifies the database conncetion