1 | <?php
|
---|
2 | //=======================================================================
|
---|
3 | // File: JPGRAPH.PHP
|
---|
4 | // Description: PHP Graph Plotting library. Base module.
|
---|
5 | // Created: 2001-01-08
|
---|
6 | // Ver: $Id: jpgraph.php 1924 2010-01-11 14:03:26Z ljp $
|
---|
7 | //
|
---|
8 | // Copyright (c) Asial Corporation. All rights reserved.
|
---|
9 | //========================================================================
|
---|
10 |
|
---|
11 | require_once('jpg-config.inc.php');
|
---|
12 | require_once('jpgraph_gradient.php');
|
---|
13 | require_once('jpgraph_errhandler.inc.php');
|
---|
14 | require_once('jpgraph_ttf.inc.php');
|
---|
15 | require_once('jpgraph_rgb.inc.php');
|
---|
16 | require_once('jpgraph_text.inc.php');
|
---|
17 | require_once('jpgraph_legend.inc.php');
|
---|
18 | require_once('jpgraph_theme.inc.php');
|
---|
19 | require_once('gd_image.inc.php');
|
---|
20 |
|
---|
21 | // Version info
|
---|
22 | define('JPG_VERSION','4.2.6');
|
---|
23 |
|
---|
24 | // Minimum required PHP version
|
---|
25 | define('MIN_PHPVERSION','5.1.0');
|
---|
26 |
|
---|
27 | // Special file name to indicate that we only want to calc
|
---|
28 | // the image map in the call to Graph::Stroke() used
|
---|
29 | // internally from the GetHTMLCSIM() method.
|
---|
30 | define('_CSIM_SPECIALFILE','_csim_special_');
|
---|
31 |
|
---|
32 | // HTTP GET argument that is used with image map
|
---|
33 | // to indicate to the script to just generate the image
|
---|
34 | // and not the full CSIM HTML page.
|
---|
35 | define('_CSIM_DISPLAY','_jpg_csimd');
|
---|
36 |
|
---|
37 | // Special filename for Graph::Stroke(). If this filename is given
|
---|
38 | // then the image will NOT be streamed to browser of file. Instead the
|
---|
39 | // Stroke call will return the handler for the created GD image.
|
---|
40 | define('_IMG_HANDLER','__handle');
|
---|
41 |
|
---|
42 | // Special filename for Graph::Stroke(). If this filename is given
|
---|
43 | // the image will be stroked to a file with a name based on the script name.
|
---|
44 | define('_IMG_AUTO','auto');
|
---|
45 |
|
---|
46 | // Tick density
|
---|
47 | define("TICKD_DENSE",1);
|
---|
48 | define("TICKD_NORMAL",2);
|
---|
49 | define("TICKD_SPARSE",3);
|
---|
50 | define("TICKD_VERYSPARSE",4);
|
---|
51 |
|
---|
52 | // Side for ticks and labels.
|
---|
53 | define("SIDE_LEFT",-1);
|
---|
54 | define("SIDE_RIGHT",1);
|
---|
55 | define("SIDE_DOWN",-1);
|
---|
56 | define("SIDE_BOTTOM",-1);
|
---|
57 | define("SIDE_UP",1);
|
---|
58 | define("SIDE_TOP",1);
|
---|
59 |
|
---|
60 | // Legend type stacked vertical or horizontal
|
---|
61 | define("LEGEND_VERT",0);
|
---|
62 | define("LEGEND_HOR",1);
|
---|
63 |
|
---|
64 | // Mark types for plot marks
|
---|
65 | define("MARK_SQUARE",1);
|
---|
66 | define("MARK_UTRIANGLE",2);
|
---|
67 | define("MARK_DTRIANGLE",3);
|
---|
68 | define("MARK_DIAMOND",4);
|
---|
69 | define("MARK_CIRCLE",5);
|
---|
70 | define("MARK_FILLEDCIRCLE",6);
|
---|
71 | define("MARK_CROSS",7);
|
---|
72 | define("MARK_STAR",8);
|
---|
73 | define("MARK_X",9);
|
---|
74 | define("MARK_LEFTTRIANGLE",10);
|
---|
75 | define("MARK_RIGHTTRIANGLE",11);
|
---|
76 | define("MARK_FLASH",12);
|
---|
77 | define("MARK_IMG",13);
|
---|
78 | define("MARK_FLAG1",14);
|
---|
79 | define("MARK_FLAG2",15);
|
---|
80 | define("MARK_FLAG3",16);
|
---|
81 | define("MARK_FLAG4",17);
|
---|
82 |
|
---|
83 | // Builtin images
|
---|
84 | define("MARK_IMG_PUSHPIN",50);
|
---|
85 | define("MARK_IMG_SPUSHPIN",50);
|
---|
86 | define("MARK_IMG_LPUSHPIN",51);
|
---|
87 | define("MARK_IMG_DIAMOND",52);
|
---|
88 | define("MARK_IMG_SQUARE",53);
|
---|
89 | define("MARK_IMG_STAR",54);
|
---|
90 | define("MARK_IMG_BALL",55);
|
---|
91 | define("MARK_IMG_SBALL",55);
|
---|
92 | define("MARK_IMG_MBALL",56);
|
---|
93 | define("MARK_IMG_LBALL",57);
|
---|
94 | define("MARK_IMG_BEVEL",58);
|
---|
95 |
|
---|
96 | // Inline defines
|
---|
97 | define("INLINE_YES",1);
|
---|
98 | define("INLINE_NO",0);
|
---|
99 |
|
---|
100 | // Format for background images
|
---|
101 | define("BGIMG_FILLPLOT",1);
|
---|
102 | define("BGIMG_FILLFRAME",2);
|
---|
103 | define("BGIMG_COPY",3);
|
---|
104 | define("BGIMG_CENTER",4);
|
---|
105 | define("BGIMG_FREE",5);
|
---|
106 |
|
---|
107 | // Depth of objects
|
---|
108 | define("DEPTH_BACK",0);
|
---|
109 | define("DEPTH_FRONT",1);
|
---|
110 |
|
---|
111 | // Direction
|
---|
112 | define("VERTICAL",1);
|
---|
113 | define("HORIZONTAL",0);
|
---|
114 |
|
---|
115 | // Axis styles for scientific style axis
|
---|
116 | define('AXSTYLE_SIMPLE',1);
|
---|
117 | define('AXSTYLE_BOXIN',2);
|
---|
118 | define('AXSTYLE_BOXOUT',3);
|
---|
119 | define('AXSTYLE_YBOXIN',4);
|
---|
120 | define('AXSTYLE_YBOXOUT',5);
|
---|
121 |
|
---|
122 | // Style for title backgrounds
|
---|
123 | define('TITLEBKG_STYLE1',1);
|
---|
124 | define('TITLEBKG_STYLE2',2);
|
---|
125 | define('TITLEBKG_STYLE3',3);
|
---|
126 | define('TITLEBKG_FRAME_NONE',0);
|
---|
127 | define('TITLEBKG_FRAME_FULL',1);
|
---|
128 | define('TITLEBKG_FRAME_BOTTOM',2);
|
---|
129 | define('TITLEBKG_FRAME_BEVEL',3);
|
---|
130 | define('TITLEBKG_FILLSTYLE_HSTRIPED',1);
|
---|
131 | define('TITLEBKG_FILLSTYLE_VSTRIPED',2);
|
---|
132 | define('TITLEBKG_FILLSTYLE_SOLID',3);
|
---|
133 |
|
---|
134 | // Styles for axis labels background
|
---|
135 | define('LABELBKG_NONE',0);
|
---|
136 | define('LABELBKG_XAXIS',1);
|
---|
137 | define('LABELBKG_YAXIS',2);
|
---|
138 | define('LABELBKG_XAXISFULL',3);
|
---|
139 | define('LABELBKG_YAXISFULL',4);
|
---|
140 | define('LABELBKG_XYFULL',5);
|
---|
141 | define('LABELBKG_XY',6);
|
---|
142 |
|
---|
143 |
|
---|
144 | // Style for background gradient fills
|
---|
145 | define('BGRAD_FRAME',1);
|
---|
146 | define('BGRAD_MARGIN',2);
|
---|
147 | define('BGRAD_PLOT',3);
|
---|
148 |
|
---|
149 | // Width of tab titles
|
---|
150 | define('TABTITLE_WIDTHFIT',0);
|
---|
151 | define('TABTITLE_WIDTHFULL',-1);
|
---|
152 |
|
---|
153 | // Defines for 3D skew directions
|
---|
154 | define('SKEW3D_UP',0);
|
---|
155 | define('SKEW3D_DOWN',1);
|
---|
156 | define('SKEW3D_LEFT',2);
|
---|
157 | define('SKEW3D_RIGHT',3);
|
---|
158 |
|
---|
159 | // For internal use only
|
---|
160 | define("_JPG_DEBUG",false);
|
---|
161 | define("_FORCE_IMGTOFILE",false);
|
---|
162 | define("_FORCE_IMGDIR",'/tmp/jpgimg/');
|
---|
163 |
|
---|
164 |
|
---|
165 | //
|
---|
166 | // Automatic settings of path for cache and font directory
|
---|
167 | // if they have not been previously specified
|
---|
168 | //
|
---|
169 | if(USE_CACHE) {
|
---|
170 | if (!defined('CACHE_DIR')) {
|
---|
171 | if ( strstr( PHP_OS, 'WIN') ) {
|
---|
172 | if( empty($_SERVER['TEMP']) ) {
|
---|
173 | $t = new ErrMsgText();
|
---|
174 | $msg = $t->Get(11,$file,$lineno);
|
---|
175 | die($msg);
|
---|
176 | }
|
---|
177 | else {
|
---|
178 | define('CACHE_DIR', $_SERVER['TEMP'] . '/');
|
---|
179 | }
|
---|
180 | } else {
|
---|
181 | define('CACHE_DIR','/tmp/jpgraph_cache/');
|
---|
182 | }
|
---|
183 | }
|
---|
184 | }
|
---|
185 | elseif( !defined('CACHE_DIR') ) {
|
---|
186 | define('CACHE_DIR', '');
|
---|
187 | }
|
---|
188 |
|
---|
189 | //
|
---|
190 | // Setup path for western/latin TTF fonts
|
---|
191 | //
|
---|
192 | if (!defined('TTF_DIR')) {
|
---|
193 | if (strstr( PHP_OS, 'WIN') ) {
|
---|
194 | $sroot = getenv('SystemRoot');
|
---|
195 | if( empty($sroot) ) {
|
---|
196 | $t = new ErrMsgText();
|
---|
197 | $msg = $t->Get(12,$file,$lineno);
|
---|
198 | die($msg);
|
---|
199 | }
|
---|
200 | else {
|
---|
201 | define('TTF_DIR', $sroot.'/fonts/');
|
---|
202 | }
|
---|
203 | } else {
|
---|
204 | define('TTF_DIR','/usr/share/fonts/truetype/');
|
---|
205 | }
|
---|
206 | }
|
---|
207 |
|
---|
208 | //
|
---|
209 | // Setup path for MultiByte TTF fonts (japanese, chinese etc.)
|
---|
210 | //
|
---|
211 | if (!defined('MBTTF_DIR')) {
|
---|
212 | if (strstr( PHP_OS, 'WIN') ) {
|
---|
213 | $sroot = getenv('SystemRoot');
|
---|
214 | if( empty($sroot) ) {
|
---|
215 | $t = new ErrMsgText();
|
---|
216 | $msg = $t->Get(12,$file,$lineno);
|
---|
217 | die($msg);
|
---|
218 | }
|
---|
219 | else {
|
---|
220 | define('MBTTF_DIR', $sroot.'/fonts/');
|
---|
221 | }
|
---|
222 | } else {
|
---|
223 | define('MBTTF_DIR','/usr/share/fonts/truetype/');
|
---|
224 | }
|
---|
225 | }
|
---|
226 |
|
---|
227 | //
|
---|
228 | // Check minimum PHP version
|
---|
229 | //
|
---|
230 | function CheckPHPVersion($aMinVersion) {
|
---|
231 | list($majorC, $minorC, $editC) = preg_split('/[\/.-]/', PHP_VERSION);
|
---|
232 | list($majorR, $minorR, $editR) = preg_split('/[\/.-]/', $aMinVersion);
|
---|
233 |
|
---|
234 | if ($majorC < $majorR) return false;
|
---|
235 |
|
---|
236 | if ($majorC == $majorR) {
|
---|
237 | if($minorC < $minorR) return false;
|
---|
238 |
|
---|
239 | if($minorC == $minorR){
|
---|
240 | if($editC < $editR) return false;
|
---|
241 | }
|
---|
242 | }
|
---|
243 |
|
---|
244 | return true;
|
---|
245 | }
|
---|
246 |
|
---|
247 | //
|
---|
248 | // Make sure PHP version is high enough
|
---|
249 | //
|
---|
250 | if( !CheckPHPVersion(MIN_PHPVERSION) ) {
|
---|
251 | JpGraphError::RaiseL(13,PHP_VERSION,MIN_PHPVERSION);
|
---|
252 | die();
|
---|
253 | }
|
---|
254 |
|
---|
255 | //
|
---|
256 | // Make GD sanity check
|
---|
257 | //
|
---|
258 | if( !function_exists("imagetypes") || !function_exists('imagecreatefromstring') ) {
|
---|
259 | JpGraphError::RaiseL(25001);
|
---|
260 | //("This PHP installation is not configured with the GD library. Please recompile PHP with GD support to run JpGraph. (Neither function imagetypes() nor imagecreatefromstring() does exist)");
|
---|
261 | }
|
---|
262 |
|
---|
263 | //
|
---|
264 | // Setup PHP error handler
|
---|
265 | //
|
---|
266 | function _phpErrorHandler($errno,$errmsg,$filename, $linenum, $vars) {
|
---|
267 | // Respect current error level
|
---|
268 | if( $errno & error_reporting() ) {
|
---|
269 | JpGraphError::RaiseL(25003,basename($filename),$linenum,$errmsg);
|
---|
270 | }
|
---|
271 | }
|
---|
272 |
|
---|
273 | if( INSTALL_PHP_ERR_HANDLER ) {
|
---|
274 | set_error_handler("_phpErrorHandler");
|
---|
275 | }
|
---|
276 |
|
---|
277 | //
|
---|
278 | // Check if there were any warnings, perhaps some wrong includes by the user. In this
|
---|
279 | // case we raise it immediately since otherwise the image will not show and makes
|
---|
280 | // debugging difficult. This is controlled by the user setting CATCH_PHPERRMSG
|
---|
281 | //
|
---|
282 | if( isset($GLOBALS['php_errormsg']) && CATCH_PHPERRMSG && !preg_match('/|Deprecated|/i', $GLOBALS['php_errormsg']) ) {
|
---|
283 | JpGraphError::RaiseL(25004,$GLOBALS['php_errormsg']);
|
---|
284 | }
|
---|
285 |
|
---|
286 | // Useful mathematical function
|
---|
287 | function sign($a) {return $a >= 0 ? 1 : -1;}
|
---|
288 |
|
---|
289 | //
|
---|
290 | // Utility function to generate an image name based on the filename we
|
---|
291 | // are running from and assuming we use auto detection of graphic format
|
---|
292 | // (top level), i.e it is safe to call this function
|
---|
293 | // from a script that uses JpGraph
|
---|
294 | //
|
---|
295 | function GenImgName() {
|
---|
296 | // Determine what format we should use when we save the images
|
---|
297 | $supported = imagetypes();
|
---|
298 | if( $supported & IMG_PNG ) $img_format="png";
|
---|
299 | elseif( $supported & IMG_GIF ) $img_format="gif";
|
---|
300 | elseif( $supported & IMG_JPG ) $img_format="jpeg";
|
---|
301 | elseif( $supported & IMG_WBMP ) $img_format="wbmp";
|
---|
302 | elseif( $supported & IMG_XPM ) $img_format="xpm";
|
---|
303 |
|
---|
304 |
|
---|
305 | if( !isset($_SERVER['PHP_SELF']) ) {
|
---|
306 | JpGraphError::RaiseL(25005);
|
---|
307 | //(" Can't access PHP_SELF, PHP global variable. You can't run PHP from command line if you want to use the 'auto' naming of cache or image files.");
|
---|
308 | }
|
---|
309 | $fname = basename($_SERVER['PHP_SELF']);
|
---|
310 | if( !empty($_SERVER['QUERY_STRING']) ) {
|
---|
311 | $q = @$_SERVER['QUERY_STRING'];
|
---|
312 | $fname .= '_'.preg_replace("/\W/", "_", $q).'.'.$img_format;
|
---|
313 | }
|
---|
314 | else {
|
---|
315 | $fname = substr($fname,0,strlen($fname)-4).'.'.$img_format;
|
---|
316 | }
|
---|
317 | return $fname;
|
---|
318 | }
|
---|
319 |
|
---|
320 | //===================================================
|
---|
321 | // CLASS JpgTimer
|
---|
322 | // Description: General timing utility class to handle
|
---|
323 | // time measurement of generating graphs. Multiple
|
---|
324 | // timers can be started.
|
---|
325 | //===================================================
|
---|
326 | class JpgTimer {
|
---|
327 | private $start, $idx;
|
---|
328 |
|
---|
329 | function __construct() {
|
---|
330 | $this->idx=0;
|
---|
331 | }
|
---|
332 |
|
---|
333 | // Push a new timer start on stack
|
---|
334 | function Push() {
|
---|
335 | list($ms,$s)=explode(" ",microtime());
|
---|
336 | $this->start[$this->idx++]=floor($ms*1000) + 1000*$s;
|
---|
337 | }
|
---|
338 |
|
---|
339 | // Pop the latest timer start and return the diff with the
|
---|
340 | // current time
|
---|
341 | function Pop() {
|
---|
342 | assert($this->idx>0);
|
---|
343 | list($ms,$s)=explode(" ",microtime());
|
---|
344 | $etime=floor($ms*1000) + (1000*$s);
|
---|
345 | $this->idx--;
|
---|
346 | return $etime-$this->start[$this->idx];
|
---|
347 | }
|
---|
348 | } // Class
|
---|
349 |
|
---|
350 | //===================================================
|
---|
351 | // CLASS DateLocale
|
---|
352 | // Description: Hold localized text used in dates
|
---|
353 | //===================================================
|
---|
354 | class DateLocale {
|
---|
355 |
|
---|
356 | public $iLocale = 'C'; // environmental locale be used by default
|
---|
357 | private $iDayAbb = null, $iShortDay = null, $iShortMonth = null, $iMonthName = null;
|
---|
358 |
|
---|
359 | function __construct() {
|
---|
360 | settype($this->iDayAbb, 'array');
|
---|
361 | settype($this->iShortDay, 'array');
|
---|
362 | settype($this->iShortMonth, 'array');
|
---|
363 | settype($this->iMonthName, 'array');
|
---|
364 | $this->Set('C');
|
---|
365 | }
|
---|
366 |
|
---|
367 | function Set($aLocale) {
|
---|
368 | if ( in_array($aLocale, array_keys($this->iDayAbb)) ){
|
---|
369 | $this->iLocale = $aLocale;
|
---|
370 | return TRUE; // already cached nothing else to do!
|
---|
371 | }
|
---|
372 |
|
---|
373 | $pLocale = setlocale(LC_TIME, 0); // get current locale for LC_TIME
|
---|
374 |
|
---|
375 | if (is_array($aLocale)) {
|
---|
376 | foreach ($aLocale as $loc) {
|
---|
377 | $res = @setlocale(LC_TIME, $loc);
|
---|
378 | if ( $res ) {
|
---|
379 | $aLocale = $loc;
|
---|
380 | break;
|
---|
381 | }
|
---|
382 | }
|
---|
383 | }
|
---|
384 | else {
|
---|
385 | $res = @setlocale(LC_TIME, $aLocale);
|
---|
386 | }
|
---|
387 |
|
---|
388 | if ( ! $res ) {
|
---|
389 | JpGraphError::RaiseL(25007,$aLocale);
|
---|
390 | //("You are trying to use the locale ($aLocale) which your PHP installation does not support. Hint: Use '' to indicate the default locale for this geographic region.");
|
---|
391 | return FALSE;
|
---|
392 | }
|
---|
393 |
|
---|
394 | $this->iLocale = $aLocale;
|
---|
395 | for( $i = 0, $ofs = 0 - strftime('%w'); $i < 7; $i++, $ofs++ ) {
|
---|
396 | $day = strftime('%a', strtotime("$ofs day"));
|
---|
397 | $day[0] = strtoupper($day[0]);
|
---|
398 | $this->iDayAbb[$aLocale][]= $day[0];
|
---|
399 | $this->iShortDay[$aLocale][]= $day;
|
---|
400 | }
|
---|
401 |
|
---|
402 | for($i=1; $i<=12; ++$i) {
|
---|
403 | list($short ,$full) = explode('|', strftime("%b|%B",strtotime("2001-$i-01")));
|
---|
404 | $this->iShortMonth[$aLocale][] = ucfirst($short);
|
---|
405 | $this->iMonthName [$aLocale][] = ucfirst($full);
|
---|
406 | }
|
---|
407 |
|
---|
408 | setlocale(LC_TIME, $pLocale);
|
---|
409 |
|
---|
410 | return TRUE;
|
---|
411 | }
|
---|
412 |
|
---|
413 |
|
---|
414 | function GetDayAbb() {
|
---|
415 | return $this->iDayAbb[$this->iLocale];
|
---|
416 | }
|
---|
417 |
|
---|
418 | function GetShortDay() {
|
---|
419 | return $this->iShortDay[$this->iLocale];
|
---|
420 | }
|
---|
421 |
|
---|
422 | function GetShortMonth() {
|
---|
423 | return $this->iShortMonth[$this->iLocale];
|
---|
424 | }
|
---|
425 |
|
---|
426 | function GetShortMonthName($aNbr) {
|
---|
427 | return $this->iShortMonth[$this->iLocale][$aNbr];
|
---|
428 | }
|
---|
429 |
|
---|
430 | function GetLongMonthName($aNbr) {
|
---|
431 | return $this->iMonthName[$this->iLocale][$aNbr];
|
---|
432 | }
|
---|
433 |
|
---|
434 | function GetMonth() {
|
---|
435 | return $this->iMonthName[$this->iLocale];
|
---|
436 | }
|
---|
437 | }
|
---|
438 |
|
---|
439 | // Global object handlers
|
---|
440 | $gDateLocale = new DateLocale();
|
---|
441 | $gJpgDateLocale = new DateLocale();
|
---|
442 |
|
---|
443 | //=======================================================
|
---|
444 | // CLASS Footer
|
---|
445 | // Description: Encapsulates the footer line in the Graph
|
---|
446 | //=======================================================
|
---|
447 | class Footer {
|
---|
448 | public $iLeftMargin = 3, $iRightMargin = 3, $iBottomMargin = 3 ;
|
---|
449 | public $left,$center,$right;
|
---|
450 | private $iTimer=null, $itimerpoststring='';
|
---|
451 |
|
---|
452 | function __construct() {
|
---|
453 | $this->left = new Text();
|
---|
454 | $this->left->ParagraphAlign('left');
|
---|
455 | $this->center = new Text();
|
---|
456 | $this->center->ParagraphAlign('center');
|
---|
457 | $this->right = new Text();
|
---|
458 | $this->right->ParagraphAlign('right');
|
---|
459 | }
|
---|
460 |
|
---|
461 | function SetTimer($aTimer,$aTimerPostString='') {
|
---|
462 | $this->iTimer = $aTimer;
|
---|
463 | $this->itimerpoststring = $aTimerPostString;
|
---|
464 | }
|
---|
465 |
|
---|
466 | function SetMargin($aLeft=3,$aRight=3,$aBottom=3) {
|
---|
467 | $this->iLeftMargin = $aLeft;
|
---|
468 | $this->iRightMargin = $aRight;
|
---|
469 | $this->iBottomMargin = $aBottom;
|
---|
470 | }
|
---|
471 |
|
---|
472 | function Stroke($aImg) {
|
---|
473 | $y = $aImg->height - $this->iBottomMargin;
|
---|
474 | $x = $this->iLeftMargin;
|
---|
475 | $this->left->Align('left','bottom');
|
---|
476 | $this->left->Stroke($aImg,$x,$y);
|
---|
477 |
|
---|
478 | $x = ($aImg->width - $this->iLeftMargin - $this->iRightMargin)/2;
|
---|
479 | $this->center->Align('center','bottom');
|
---|
480 | $this->center->Stroke($aImg,$x,$y);
|
---|
481 |
|
---|
482 | $x = $aImg->width - $this->iRightMargin;
|
---|
483 | $this->right->Align('right','bottom');
|
---|
484 | if( $this->iTimer != null ) {
|
---|
485 | $this->right->Set( $this->right->t . sprintf('%.3f',$this->iTimer->Pop()/1000.0) . $this->itimerpoststring );
|
---|
486 | }
|
---|
487 | $this->right->Stroke($aImg,$x,$y);
|
---|
488 | }
|
---|
489 | }
|
---|
490 |
|
---|
491 |
|
---|
492 | //===================================================
|
---|
493 | // CLASS Graph
|
---|
494 | // Description: Main class to handle graphs
|
---|
495 | //===================================================
|
---|
496 | class Graph {
|
---|
497 | public $cache=null; // Cache object (singleton)
|
---|
498 | public $img=null; // Img object (singleton)
|
---|
499 | public $plots=array(); // Array of all plot object in the graph (for Y 1 axis)
|
---|
500 | public $y2plots=array(); // Array of all plot object in the graph (for Y 2 axis)
|
---|
501 | public $ynplots=array();
|
---|
502 | public $xscale=null; // X Scale object (could be instance of LinearScale or LogScale
|
---|
503 | public $yscale=null,$y2scale=null, $ynscale=array();
|
---|
504 | public $iIcons = array(); // Array of Icons to add to
|
---|
505 | public $cache_name; // File name to be used for the current graph in the cache directory
|
---|
506 | public $xgrid=null; // X Grid object (linear or logarithmic)
|
---|
507 | public $ygrid=null,$y2grid=null; //dito for Y
|
---|
508 | public $doframe,$frame_color, $frame_weight; // Frame around graph
|
---|
509 | public $boxed=false, $box_color='black', $box_weight=1; // Box around plot area
|
---|
510 | public $doshadow=false,$shadow_width=4,$shadow_color='gray@0.5'; // Shadow for graph
|
---|
511 | public $xaxis=null; // X-axis (instane of Axis class)
|
---|
512 | public $yaxis=null, $y2axis=null, $ynaxis=array(); // Y axis (instance of Axis class)
|
---|
513 | public $margin_color; // Margin color of graph
|
---|
514 | public $plotarea_color=array(255,255,255); // Plot area color
|
---|
515 | public $title,$subtitle,$subsubtitle; // Title and subtitle(s) text object
|
---|
516 | public $axtype="linlin"; // Type of axis
|
---|
517 | public $xtick_factor,$ytick_factor; // Factor to determine the maximum number of ticks depending on the plot width
|
---|
518 | public $texts=null, $y2texts=null; // Text object to ge shown in the graph
|
---|
519 | public $lines=null, $y2lines=null;
|
---|
520 | public $bands=null, $y2bands=null;
|
---|
521 | public $text_scale_off=0, $text_scale_abscenteroff=-1; // Text scale in fractions and for centering bars
|
---|
522 | public $background_image='',$background_image_type=-1,$background_image_format="png";
|
---|
523 | public $background_image_bright=0,$background_image_contr=0,$background_image_sat=0;
|
---|
524 | public $background_image_xpos=0,$background_image_ypos=0;
|
---|
525 | public $image_bright=0, $image_contr=0, $image_sat=0;
|
---|
526 | public $inline;
|
---|
527 | public $showcsim=0,$csimcolor="red";//debug stuff, draw the csim boundaris on the image if <>0
|
---|
528 | public $grid_depth=DEPTH_BACK; // Draw grid under all plots as default
|
---|
529 | public $iAxisStyle = AXSTYLE_SIMPLE;
|
---|
530 | public $iCSIMdisplay=false,$iHasStroked = false;
|
---|
531 | public $footer;
|
---|
532 | public $csimcachename = '', $csimcachetimeout = 0, $iCSIMImgAlt='';
|
---|
533 | public $iDoClipping = false;
|
---|
534 | public $y2orderback=true;
|
---|
535 | public $tabtitle;
|
---|
536 | public $bkg_gradtype=-1,$bkg_gradstyle=BGRAD_MARGIN;
|
---|
537 | public $bkg_gradfrom='navy', $bkg_gradto='silver';
|
---|
538 | public $plot_gradtype=-1,$plot_gradstyle=BGRAD_MARGIN;
|
---|
539 | public $plot_gradfrom='silver', $plot_gradto='navy';
|
---|
540 |
|
---|
541 | public $titlebackground = false;
|
---|
542 | public $titlebackground_color = 'lightblue',
|
---|
543 | $titlebackground_style = 1,
|
---|
544 | $titlebackground_framecolor,
|
---|
545 | $titlebackground_framestyle,
|
---|
546 | $titlebackground_frameweight,
|
---|
547 | $titlebackground_bevelheight;
|
---|
548 | public $titlebkg_fillstyle=TITLEBKG_FILLSTYLE_SOLID;
|
---|
549 | public $titlebkg_scolor1='black',$titlebkg_scolor2='white';
|
---|
550 | public $framebevel, $framebeveldepth;
|
---|
551 | public $framebevelborder, $framebevelbordercolor;
|
---|
552 | public $framebevelcolor1, $framebevelcolor2;
|
---|
553 | public $background_image_mix=100;
|
---|
554 | public $background_cflag = '';
|
---|
555 | public $background_cflag_type = BGIMG_FILLPLOT;
|
---|
556 | public $background_cflag_mix = 100;
|
---|
557 | public $iImgTrans=false,
|
---|
558 | $iImgTransHorizon = 100,$iImgTransSkewDist=150,
|
---|
559 | $iImgTransDirection = 1, $iImgTransMinSize = true,
|
---|
560 | $iImgTransFillColor='white',$iImgTransHighQ=false,
|
---|
561 | $iImgTransBorder=false,$iImgTransHorizonPos=0.5;
|
---|
562 | public $legend;
|
---|
563 | public $graph_theme;
|
---|
564 | protected $iYAxisDeltaPos=50;
|
---|
565 | protected $iIconDepth=DEPTH_BACK;
|
---|
566 | protected $iAxisLblBgType = 0,
|
---|
567 | $iXAxisLblBgFillColor = 'lightgray', $iXAxisLblBgColor = 'black',
|
---|
568 | $iYAxisLblBgFillColor = 'lightgray', $iYAxisLblBgColor = 'black';
|
---|
569 | protected $iTables=NULL;
|
---|
570 |
|
---|
571 | protected $isRunningClear = false;
|
---|
572 | protected $inputValues;
|
---|
573 | protected $isAfterSetScale = false;
|
---|
574 |
|
---|
575 | // aWIdth Width in pixels of image
|
---|
576 | // aHeight Height in pixels of image
|
---|
577 | // aCachedName Name for image file in cache directory
|
---|
578 | // aTimeOut Timeout in minutes for image in cache
|
---|
579 | // aInline If true the image is streamed back in the call to Stroke()
|
---|
580 | // If false the image is just created in the cache
|
---|
581 | function __construct($aWidth=300,$aHeight=200,$aCachedName='',$aTimeout=0,$aInline=true) {
|
---|
582 |
|
---|
583 | if( !is_numeric($aWidth) || !is_numeric($aHeight) ) {
|
---|
584 | JpGraphError::RaiseL(25008);//('Image width/height argument in Graph::Graph() must be numeric');
|
---|
585 | }
|
---|
586 |
|
---|
587 | // Initialize frame and margin
|
---|
588 | $this->InitializeFrameAndMargin();
|
---|
589 |
|
---|
590 | // Automatically generate the image file name based on the name of the script that
|
---|
591 | // generates the graph
|
---|
592 | if( $aCachedName == 'auto' ) {
|
---|
593 | $aCachedName=GenImgName();
|
---|
594 | }
|
---|
595 |
|
---|
596 | // Should the image be streamed back to the browser or only to the cache?
|
---|
597 | $this->inline=$aInline;
|
---|
598 |
|
---|
599 | $this->img = new RotImage($aWidth,$aHeight);
|
---|
600 | $this->cache = new ImgStreamCache();
|
---|
601 |
|
---|
602 | // Window doesn't like '?' in the file name so replace it with an '_'
|
---|
603 | $aCachedName = str_replace("?","_",$aCachedName);
|
---|
604 | $this->SetupCache($aCachedName, $aTimeout);
|
---|
605 |
|
---|
606 | $this->title = new Text();
|
---|
607 | $this->title->ParagraphAlign('center');
|
---|
608 | $this->title->SetFont(FF_DEFAULT,FS_NORMAL); //FF_FONT2, FS_BOLD
|
---|
609 | $this->title->SetMargin(5);
|
---|
610 | $this->title->SetAlign('center');
|
---|
611 |
|
---|
612 | $this->subtitle = new Text();
|
---|
613 | $this->subtitle->ParagraphAlign('center');
|
---|
614 | $this->subtitle->SetMargin(3);
|
---|
615 | $this->subtitle->SetAlign('center');
|
---|
616 |
|
---|
617 | $this->subsubtitle = new Text();
|
---|
618 | $this->subsubtitle->ParagraphAlign('center');
|
---|
619 | $this->subsubtitle->SetMargin(3);
|
---|
620 | $this->subsubtitle->SetAlign('center');
|
---|
621 |
|
---|
622 | $this->legend = new Legend();
|
---|
623 | $this->footer = new Footer();
|
---|
624 |
|
---|
625 | // If the cached version exist just read it directly from the
|
---|
626 | // cache, stream it back to browser and exit
|
---|
627 | if( $aCachedName!='' && READ_CACHE && $aInline ) {
|
---|
628 | if( $this->cache->GetAndStream($this->img,$aCachedName) ) {
|
---|
629 | exit();
|
---|
630 | }
|
---|
631 | }
|
---|
632 |
|
---|
633 | $this->SetTickDensity(); // Normal density
|
---|
634 |
|
---|
635 | $this->tabtitle = new GraphTabTitle();
|
---|
636 |
|
---|
637 | if (!$this->isRunningClear) {
|
---|
638 | $this->inputValues = array();
|
---|
639 | $this->inputValues['aWidth'] = $aWidth;
|
---|
640 | $this->inputValues['aHeight'] = $aHeight;
|
---|
641 | $this->inputValues['aCachedName'] = $aCachedName;
|
---|
642 | $this->inputValues['aTimeout'] = $aTimeout;
|
---|
643 | $this->inputValues['aInline'] = $aInline;
|
---|
644 |
|
---|
645 | $theme_class = DEFAULT_THEME_CLASS;
|
---|
646 | if (class_exists($theme_class)) {
|
---|
647 | $this->graph_theme = new $theme_class();
|
---|
648 | }
|
---|
649 | }
|
---|
650 | }
|
---|
651 |
|
---|
652 | function InitializeFrameAndMargin() {
|
---|
653 | $this->doframe=true;
|
---|
654 | $this->frame_color='black';
|
---|
655 | $this->frame_weight=1;
|
---|
656 |
|
---|
657 | $this->titlebackground_framecolor = 'blue';
|
---|
658 | $this->titlebackground_framestyle = 2;
|
---|
659 | $this->titlebackground_frameweight = 1;
|
---|
660 | $this->titlebackground_bevelheight = 3;
|
---|
661 | $this->titlebkg_fillstyle=TITLEBKG_FILLSTYLE_SOLID;
|
---|
662 | $this->titlebkg_scolor1='black';
|
---|
663 | $this->titlebkg_scolor2='white';
|
---|
664 | $this->framebevel = false;
|
---|
665 | $this->framebeveldepth = 2;
|
---|
666 | $this->framebevelborder = false;
|
---|
667 | $this->framebevelbordercolor='black';
|
---|
668 | $this->framebevelcolor1='white@0.4';
|
---|
669 | $this->framebevelcolor2='black@0.4';
|
---|
670 |
|
---|
671 | $this->margin_color = array(250,250,250);
|
---|
672 | }
|
---|
673 |
|
---|
674 | function SetupCache($aFilename,$aTimeout=60) {
|
---|
675 | $this->cache_name = $aFilename;
|
---|
676 | $this->cache->SetTimeOut($aTimeout);
|
---|
677 | }
|
---|
678 |
|
---|
679 | // Enable final image perspective transformation
|
---|
680 | function Set3DPerspective($aDir=1,$aHorizon=100,$aSkewDist=120,$aQuality=false,$aFillColor='#FFFFFF',$aBorder=false,$aMinSize=true,$aHorizonPos=0.5) {
|
---|
681 | $this->iImgTrans = true;
|
---|
682 | $this->iImgTransHorizon = $aHorizon;
|
---|
683 | $this->iImgTransSkewDist= $aSkewDist;
|
---|
684 | $this->iImgTransDirection = $aDir;
|
---|
685 | $this->iImgTransMinSize = $aMinSize;
|
---|
686 | $this->iImgTransFillColor=$aFillColor;
|
---|
687 | $this->iImgTransHighQ=$aQuality;
|
---|
688 | $this->iImgTransBorder=$aBorder;
|
---|
689 | $this->iImgTransHorizonPos=$aHorizonPos;
|
---|
690 | }
|
---|
691 |
|
---|
692 | function SetUserFont($aNormal,$aBold='',$aItalic='',$aBoldIt='') {
|
---|
693 | $this->img->ttf->SetUserFont($aNormal,$aBold,$aItalic,$aBoldIt);
|
---|
694 | }
|
---|
695 |
|
---|
696 | function SetUserFont1($aNormal,$aBold='',$aItalic='',$aBoldIt='') {
|
---|
697 | $this->img->ttf->SetUserFont1($aNormal,$aBold,$aItalic,$aBoldIt);
|
---|
698 | }
|
---|
699 |
|
---|
700 | function SetUserFont2($aNormal,$aBold='',$aItalic='',$aBoldIt='') {
|
---|
701 | $this->img->ttf->SetUserFont2($aNormal,$aBold,$aItalic,$aBoldIt);
|
---|
702 | }
|
---|
703 |
|
---|
704 | function SetUserFont3($aNormal,$aBold='',$aItalic='',$aBoldIt='') {
|
---|
705 | $this->img->ttf->SetUserFont3($aNormal,$aBold,$aItalic,$aBoldIt);
|
---|
706 | }
|
---|
707 |
|
---|
708 | // Set Image format and optional quality
|
---|
709 | function SetImgFormat($aFormat,$aQuality=75) {
|
---|
710 | $this->img->SetImgFormat($aFormat,$aQuality);
|
---|
711 | }
|
---|
712 |
|
---|
713 | // Should the grid be in front or back of the plot?
|
---|
714 | function SetGridDepth($aDepth) {
|
---|
715 | $this->grid_depth=$aDepth;
|
---|
716 | }
|
---|
717 |
|
---|
718 | function SetIconDepth($aDepth) {
|
---|
719 | $this->iIconDepth=$aDepth;
|
---|
720 | }
|
---|
721 |
|
---|
722 | // Specify graph angle 0-360 degrees.
|
---|
723 | function SetAngle($aAngle) {
|
---|
724 | $this->img->SetAngle($aAngle);
|
---|
725 | }
|
---|
726 |
|
---|
727 | function SetAlphaBlending($aFlg=true) {
|
---|
728 | $this->img->SetAlphaBlending($aFlg);
|
---|
729 | }
|
---|
730 |
|
---|
731 | // Shortcut to image margin
|
---|
732 | function SetMargin($lm,$rm,$tm,$bm) {
|
---|
733 | $this->img->SetMargin($lm,$rm,$tm,$bm);
|
---|
734 | }
|
---|
735 |
|
---|
736 | function SetY2OrderBack($aBack=true) {
|
---|
737 | $this->y2orderback = $aBack;
|
---|
738 | }
|
---|
739 |
|
---|
740 | // Rotate the graph 90 degrees and set the margin
|
---|
741 | // when we have done a 90 degree rotation
|
---|
742 | function Set90AndMargin($lm=0,$rm=0,$tm=0,$bm=0) {
|
---|
743 | $adj = ($this->img->height - $this->img->width)/2;
|
---|
744 | $this->img->SetMargin($tm-$adj,$bm-$adj,$rm+$adj,$lm+$adj);
|
---|
745 | $this->img->SetCenter(floor($this->img->width/2),floor($this->img->height/2));
|
---|
746 | $this->SetAngle(90);
|
---|
747 | if( empty($this->yaxis) || empty($this->xaxis) ) {
|
---|
748 | JpgraphError::RaiseL(25009);//('You must specify what scale to use with a call to Graph::SetScale()');
|
---|
749 | }
|
---|
750 | $this->xaxis->SetLabelAlign('right','center');
|
---|
751 | $this->yaxis->SetLabelAlign('center','bottom');
|
---|
752 | }
|
---|
753 |
|
---|
754 | function SetClipping($aFlg=true) {
|
---|
755 | $this->iDoClipping = $aFlg ;
|
---|
756 | }
|
---|
757 |
|
---|
758 | // Add a plot object to the graph
|
---|
759 | function Add($aPlot) {
|
---|
760 | if( $aPlot == null ) {
|
---|
761 | JpGraphError::RaiseL(25010);//("Graph::Add() You tried to add a null plot to the graph.");
|
---|
762 | }
|
---|
763 | if( is_array($aPlot) && count($aPlot) > 0 ) {
|
---|
764 | $cl = $aPlot[0];
|
---|
765 | }
|
---|
766 | else {
|
---|
767 | $cl = $aPlot;
|
---|
768 | }
|
---|
769 |
|
---|
770 | if( $cl instanceof Text ) $this->AddText($aPlot);
|
---|
771 | elseif( class_exists('PlotLine',false) && ($cl instanceof PlotLine) ) $this->AddLine($aPlot);
|
---|
772 | elseif( class_exists('PlotBand',false) && ($cl instanceof PlotBand) ) $this->AddBand($aPlot);
|
---|
773 | elseif( class_exists('IconPlot',false) && ($cl instanceof IconPlot) ) $this->AddIcon($aPlot);
|
---|
774 | elseif( class_exists('GTextTable',false) && ($cl instanceof GTextTable) ) $this->AddTable($aPlot);
|
---|
775 | else {
|
---|
776 | if( is_array($aPlot) ) {
|
---|
777 | $this->plots = array_merge($this->plots,$aPlot);
|
---|
778 | }
|
---|
779 | else {
|
---|
780 | $this->plots[] = $aPlot;
|
---|
781 | }
|
---|
782 | }
|
---|
783 |
|
---|
784 | if ($this->graph_theme) {
|
---|
785 | $this->graph_theme->SetupPlot($aPlot);
|
---|
786 | }
|
---|
787 | }
|
---|
788 |
|
---|
789 | function AddTable($aTable) {
|
---|
790 | if( is_array($aTable) ) {
|
---|
791 | for($i=0; $i < count($aTable); ++$i ) {
|
---|
792 | $this->iTables[]=$aTable[$i];
|
---|
793 | }
|
---|
794 | }
|
---|
795 | else {
|
---|
796 | $this->iTables[] = $aTable ;
|
---|
797 | }
|
---|
798 | }
|
---|
799 |
|
---|
800 | function AddIcon($aIcon) {
|
---|
801 | if( is_array($aIcon) ) {
|
---|
802 | for($i=0; $i < count($aIcon); ++$i ) {
|
---|
803 | $this->iIcons[]=$aIcon[$i];
|
---|
804 | }
|
---|
805 | }
|
---|
806 | else {
|
---|
807 | $this->iIcons[] = $aIcon ;
|
---|
808 | }
|
---|
809 | }
|
---|
810 |
|
---|
811 | // Add plot to second Y-scale
|
---|
812 | function AddY2($aPlot) {
|
---|
813 | if( $aPlot == null ) {
|
---|
814 | JpGraphError::RaiseL(25011);//("Graph::AddY2() You tried to add a null plot to the graph.");
|
---|
815 | }
|
---|
816 |
|
---|
817 | if( is_array($aPlot) && count($aPlot) > 0 ) {
|
---|
818 | $cl = $aPlot[0];
|
---|
819 | }
|
---|
820 | else {
|
---|
821 | $cl = $aPlot;
|
---|
822 | }
|
---|
823 |
|
---|
824 | if( $cl instanceof Text ) {
|
---|
825 | $this->AddText($aPlot,true);
|
---|
826 | }
|
---|
827 | elseif( class_exists('PlotLine',false) && ($cl instanceof PlotLine) ) {
|
---|
828 | $this->AddLine($aPlot,true);
|
---|
829 | }
|
---|
830 | elseif( class_exists('PlotBand',false) && ($cl instanceof PlotBand) ) {
|
---|
831 | $this->AddBand($aPlot,true);
|
---|
832 | }
|
---|
833 | else {
|
---|
834 | $this->y2plots[] = $aPlot;
|
---|
835 | }
|
---|
836 |
|
---|
837 | if ($this->graph_theme) {
|
---|
838 | $this->graph_theme->SetupPlot($aPlot);
|
---|
839 | }
|
---|
840 | }
|
---|
841 |
|
---|
842 | // Add plot to the extra Y-axises
|
---|
843 | function AddY($aN,$aPlot) {
|
---|
844 |
|
---|
845 | if( $aPlot == null ) {
|
---|
846 | JpGraphError::RaiseL(25012);//("Graph::AddYN() You tried to add a null plot to the graph.");
|
---|
847 | }
|
---|
848 |
|
---|
849 | if( is_array($aPlot) && count($aPlot) > 0 ) {
|
---|
850 | $cl = $aPlot[0];
|
---|
851 | }
|
---|
852 | else {
|
---|
853 | $cl = $aPlot;
|
---|
854 | }
|
---|
855 |
|
---|
856 | if( ($cl instanceof Text) ||
|
---|
857 | (class_exists('PlotLine',false) && ($cl instanceof PlotLine)) ||
|
---|
858 | (class_exists('PlotBand',false) && ($cl instanceof PlotBand)) ) {
|
---|
859 | JpGraph::RaiseL(25013);//('You can only add standard plots to multiple Y-axis');
|
---|
860 | }
|
---|
861 | else {
|
---|
862 | $this->ynplots[$aN][] = $aPlot;
|
---|
863 | }
|
---|
864 |
|
---|
865 | if ($this->graph_theme) {
|
---|
866 | $this->graph_theme->SetupPlot($aPlot);
|
---|
867 | }
|
---|
868 | }
|
---|
869 |
|
---|
870 | // Add text object to the graph
|
---|
871 | function AddText($aTxt,$aToY2=false) {
|
---|
872 | if( $aTxt == null ) {
|
---|
873 | JpGraphError::RaiseL(25014);//("Graph::AddText() You tried to add a null text to the graph.");
|
---|
874 | }
|
---|
875 | if( $aToY2 ) {
|
---|
876 | if( is_array($aTxt) ) {
|
---|
877 | for($i=0; $i < count($aTxt); ++$i ) {
|
---|
878 | $this->y2texts[]=$aTxt[$i];
|
---|
879 | }
|
---|
880 | }
|
---|
881 | else {
|
---|
882 | $this->y2texts[] = $aTxt;
|
---|
883 | }
|
---|
884 | }
|
---|
885 | else {
|
---|
886 | if( is_array($aTxt) ) {
|
---|
887 | for($i=0; $i < count($aTxt); ++$i ) {
|
---|
888 | $this->texts[]=$aTxt[$i];
|
---|
889 | }
|
---|
890 | }
|
---|
891 | else {
|
---|
892 | $this->texts[] = $aTxt;
|
---|
893 | }
|
---|
894 | }
|
---|
895 | }
|
---|
896 |
|
---|
897 | // Add a line object (class PlotLine) to the graph
|
---|
898 | function AddLine($aLine,$aToY2=false) {
|
---|
899 | if( $aLine == null ) {
|
---|
900 | JpGraphError::RaiseL(25015);//("Graph::AddLine() You tried to add a null line to the graph.");
|
---|
901 | }
|
---|
902 |
|
---|
903 | if( $aToY2 ) {
|
---|
904 | if( is_array($aLine) ) {
|
---|
905 | for($i=0; $i < count($aLine); ++$i ) {
|
---|
906 | //$this->y2lines[]=$aLine[$i];
|
---|
907 | $this->y2plots[]=$aLine[$i];
|
---|
908 | }
|
---|
909 | }
|
---|
910 | else {
|
---|
911 | //$this->y2lines[] = $aLine;
|
---|
912 | $this->y2plots[]=$aLine;
|
---|
913 | }
|
---|
914 | }
|
---|
915 | else {
|
---|
916 | if( is_array($aLine) ) {
|
---|
917 | for($i=0; $i<count($aLine); ++$i ) {
|
---|
918 | //$this->lines[]=$aLine[$i];
|
---|
919 | $this->plots[]=$aLine[$i];
|
---|
920 | }
|
---|
921 | }
|
---|
922 | else {
|
---|
923 | //$this->lines[] = $aLine;
|
---|
924 | $this->plots[] = $aLine;
|
---|
925 | }
|
---|
926 | }
|
---|
927 | }
|
---|
928 |
|
---|
929 | // Add vertical or horizontal band
|
---|
930 | function AddBand($aBand,$aToY2=false) {
|
---|
931 | if( $aBand == null ) {
|
---|
932 | JpGraphError::RaiseL(25016);//(" Graph::AddBand() You tried to add a null band to the graph.");
|
---|
933 | }
|
---|
934 |
|
---|
935 | if( $aToY2 ) {
|
---|
936 | if( is_array($aBand) ) {
|
---|
937 | for($i=0; $i < count($aBand); ++$i ) {
|
---|
938 | $this->y2bands[] = $aBand[$i];
|
---|
939 | }
|
---|
940 | }
|
---|
941 | else {
|
---|
942 | $this->y2bands[] = $aBand;
|
---|
943 | }
|
---|
944 | }
|
---|
945 | else {
|
---|
946 | if( is_array($aBand) ) {
|
---|
947 | for($i=0; $i < count($aBand); ++$i ) {
|
---|
948 | $this->bands[] = $aBand[$i];
|
---|
949 | }
|
---|
950 | }
|
---|
951 | else {
|
---|
952 | $this->bands[] = $aBand;
|
---|
953 | }
|
---|
954 | }
|
---|
955 | }
|
---|
956 |
|
---|
957 | function SetPlotGradient($aFrom='navy',$aTo='silver',$aGradType=2) {
|
---|
958 | $this->plot_gradtype=$aGradType;
|
---|
959 | $this->plot_gradfrom = $aFrom;
|
---|
960 | $this->plot_gradto = $aTo;
|
---|
961 | }
|
---|
962 |
|
---|
963 | function SetBackgroundGradient($aFrom='navy',$aTo='silver',$aGradType=2,$aStyle=BGRAD_FRAME) {
|
---|
964 | $this->bkg_gradtype=$aGradType;
|
---|
965 | $this->bkg_gradstyle=$aStyle;
|
---|
966 | $this->bkg_gradfrom = $aFrom;
|
---|
967 | $this->bkg_gradto = $aTo;
|
---|
968 | }
|
---|
969 |
|
---|
970 | // Set a country flag in the background
|
---|
971 | function SetBackgroundCFlag($aName,$aBgType=BGIMG_FILLPLOT,$aMix=100) {
|
---|
972 | $this->background_cflag = $aName;
|
---|
973 | $this->background_cflag_type = $aBgType;
|
---|
974 | $this->background_cflag_mix = $aMix;
|
---|
975 | }
|
---|
976 |
|
---|
977 | // Alias for the above method
|
---|
978 | function SetBackgroundCountryFlag($aName,$aBgType=BGIMG_FILLPLOT,$aMix=100) {
|
---|
979 | $this->background_cflag = $aName;
|
---|
980 | $this->background_cflag_type = $aBgType;
|
---|
981 | $this->background_cflag_mix = $aMix;
|
---|
982 | }
|
---|
983 |
|
---|
984 |
|
---|
985 | // Specify a background image
|
---|
986 | function SetBackgroundImage($aFileName,$aBgType=BGIMG_FILLPLOT,$aImgFormat='auto') {
|
---|
987 |
|
---|
988 | // Get extension to determine image type
|
---|
989 | if( $aImgFormat == 'auto' ) {
|
---|
990 | $e = explode('.',$aFileName);
|
---|
991 | if( !$e ) {
|
---|
992 | JpGraphError::RaiseL(25018,$aFileName);//('Incorrect file name for Graph::SetBackgroundImage() : '.$aFileName.' Must have a valid image extension (jpg,gif,png) when using autodetection of image type');
|
---|
993 | }
|
---|
994 |
|
---|
995 | $valid_formats = array('png', 'jpg', 'gif');
|
---|
996 | $aImgFormat = strtolower($e[count($e)-1]);
|
---|
997 | if ($aImgFormat == 'jpeg') {
|
---|
998 | $aImgFormat = 'jpg';
|
---|
999 | }
|
---|
1000 | elseif (!in_array($aImgFormat, $valid_formats) ) {
|
---|
1001 | JpGraphError::RaiseL(25019,$aImgFormat);//('Unknown file extension ($aImgFormat) in Graph::SetBackgroundImage() for filename: '.$aFileName);
|
---|
1002 | }
|
---|
1003 | }
|
---|
1004 |
|
---|
1005 | $this->background_image = $aFileName;
|
---|
1006 | $this->background_image_type=$aBgType;
|
---|
1007 | $this->background_image_format=$aImgFormat;
|
---|
1008 | }
|
---|
1009 |
|
---|
1010 | function SetBackgroundImageMix($aMix) {
|
---|
1011 | $this->background_image_mix = $aMix ;
|
---|
1012 | }
|
---|
1013 |
|
---|
1014 | // Adjust background image position
|
---|
1015 | function SetBackgroundImagePos($aXpos,$aYpos) {
|
---|
1016 | $this->background_image_xpos = $aXpos ;
|
---|
1017 | $this->background_image_ypos = $aYpos ;
|
---|
1018 | }
|
---|
1019 |
|
---|
1020 | // Specify axis style (boxed or single)
|
---|
1021 | function SetAxisStyle($aStyle) {
|
---|
1022 | $this->iAxisStyle = $aStyle ;
|
---|
1023 | }
|
---|
1024 |
|
---|
1025 | // Set a frame around the plot area
|
---|
1026 | function SetBox($aDrawPlotFrame=true,$aPlotFrameColor=array(0,0,0),$aPlotFrameWeight=1) {
|
---|
1027 | $this->boxed = $aDrawPlotFrame;
|
---|
1028 | $this->box_weight = $aPlotFrameWeight;
|
---|
1029 | $this->box_color = $aPlotFrameColor;
|
---|
1030 | }
|
---|
1031 |
|
---|
1032 | // Specify color for the plotarea (not the margins)
|
---|
1033 | function SetColor($aColor) {
|
---|
1034 | $this->plotarea_color=$aColor;
|
---|
1035 | }
|
---|
1036 |
|
---|
1037 | // Specify color for the margins (all areas outside the plotarea)
|
---|
1038 | function SetMarginColor($aColor) {
|
---|
1039 | $this->margin_color=$aColor;
|
---|
1040 | }
|
---|
1041 |
|
---|
1042 | // Set a frame around the entire image
|
---|
1043 | function SetFrame($aDrawImgFrame=true,$aImgFrameColor=array(0,0,0),$aImgFrameWeight=1) {
|
---|
1044 | $this->doframe = $aDrawImgFrame;
|
---|
1045 | $this->frame_color = $aImgFrameColor;
|
---|
1046 | $this->frame_weight = $aImgFrameWeight;
|
---|
1047 | }
|
---|
1048 |
|
---|
1049 | function SetFrameBevel($aDepth=3,$aBorder=false,$aBorderColor='black',$aColor1='white@0.4',$aColor2='darkgray@0.4',$aFlg=true) {
|
---|
1050 | $this->framebevel = $aFlg ;
|
---|
1051 | $this->framebeveldepth = $aDepth ;
|
---|
1052 | $this->framebevelborder = $aBorder ;
|
---|
1053 | $this->framebevelbordercolor = $aBorderColor ;
|
---|
1054 | $this->framebevelcolor1 = $aColor1 ;
|
---|
1055 | $this->framebevelcolor2 = $aColor2 ;
|
---|
1056 |
|
---|
1057 | $this->doshadow = false ;
|
---|
1058 | }
|
---|
1059 |
|
---|
1060 | // Set the shadow around the whole image
|
---|
1061 | function SetShadow($aShowShadow=true,$aShadowWidth=5,$aShadowColor='darkgray') {
|
---|
1062 | $this->doshadow = $aShowShadow;
|
---|
1063 | $this->shadow_color = $aShadowColor;
|
---|
1064 | $this->shadow_width = $aShadowWidth;
|
---|
1065 | $this->footer->iBottomMargin += $aShadowWidth;
|
---|
1066 | $this->footer->iRightMargin += $aShadowWidth;
|
---|
1067 | }
|
---|
1068 |
|
---|
1069 | // Specify x,y scale. Note that if you manually specify the scale
|
---|
1070 | // you must also specify the tick distance with a call to Ticks::Set()
|
---|
1071 | function SetScale($aAxisType,$aYMin=1,$aYMax=1,$aXMin=1,$aXMax=1) {
|
---|
1072 | $this->axtype = $aAxisType;
|
---|
1073 |
|
---|
1074 | if( $aYMax < $aYMin || $aXMax < $aXMin ) {
|
---|
1075 | JpGraphError::RaiseL(25020);//('Graph::SetScale(): Specified Max value must be larger than the specified Min value.');
|
---|
1076 | }
|
---|
1077 |
|
---|
1078 | $yt=substr($aAxisType,-3,3);
|
---|
1079 | if( $yt == 'lin' ) {
|
---|
1080 | $this->yscale = new LinearScale($aYMin,$aYMax);
|
---|
1081 | }
|
---|
1082 | elseif( $yt == 'int' ) {
|
---|
1083 | $this->yscale = new LinearScale($aYMin,$aYMax);
|
---|
1084 | $this->yscale->SetIntScale();
|
---|
1085 | }
|
---|
1086 | elseif( $yt == 'log' ) {
|
---|
1087 | $this->yscale = new LogScale($aYMin,$aYMax);
|
---|
1088 | }
|
---|
1089 | else {
|
---|
1090 | JpGraphError::RaiseL(25021,$aAxisType);//("Unknown scale specification for Y-scale. ($aAxisType)");
|
---|
1091 | }
|
---|
1092 |
|
---|
1093 | $xt=substr($aAxisType,0,3);
|
---|
1094 | if( $xt == 'lin' || $xt == 'tex' ) {
|
---|
1095 | $this->xscale = new LinearScale($aXMin,$aXMax,'x');
|
---|
1096 | $this->xscale->textscale = ($xt == 'tex');
|
---|
1097 | }
|
---|
1098 | elseif( $xt == 'int' ) {
|
---|
1099 | $this->xscale = new LinearScale($aXMin,$aXMax,'x');
|
---|
1100 | $this->xscale->SetIntScale();
|
---|
1101 | }
|
---|
1102 | elseif( $xt == 'dat' ) {
|
---|
1103 | $this->xscale = new DateScale($aXMin,$aXMax,'x');
|
---|
1104 | }
|
---|
1105 | elseif( $xt == 'log' ) {
|
---|
1106 | $this->xscale = new LogScale($aXMin,$aXMax,'x');
|
---|
1107 | }
|
---|
1108 | else {
|
---|
1109 | JpGraphError::RaiseL(25022,$aAxisType);//(" Unknown scale specification for X-scale. ($aAxisType)");
|
---|
1110 | }
|
---|
1111 |
|
---|
1112 | $this->xaxis = new Axis($this->img,$this->xscale);
|
---|
1113 | $this->yaxis = new Axis($this->img,$this->yscale);
|
---|
1114 | $this->xgrid = new Grid($this->xaxis);
|
---|
1115 | $this->ygrid = new Grid($this->yaxis);
|
---|
1116 | $this->ygrid->Show();
|
---|
1117 |
|
---|
1118 |
|
---|
1119 | if (!$this->isRunningClear) {
|
---|
1120 | $this->inputValues['aAxisType'] = $aAxisType;
|
---|
1121 | $this->inputValues['aYMin'] = $aYMin;
|
---|
1122 | $this->inputValues['aYMax'] = $aYMax;
|
---|
1123 | $this->inputValues['aXMin'] = $aXMin;
|
---|
1124 | $this->inputValues['aXMax'] = $aXMax;
|
---|
1125 |
|
---|
1126 | if ($this->graph_theme) {
|
---|
1127 | $this->graph_theme->ApplyGraph($this);
|
---|
1128 | }
|
---|
1129 | }
|
---|
1130 |
|
---|
1131 | $this->isAfterSetScale = true;
|
---|
1132 | }
|
---|
1133 |
|
---|
1134 | // Specify secondary Y scale
|
---|
1135 | function SetY2Scale($aAxisType='lin',$aY2Min=1,$aY2Max=1) {
|
---|
1136 | if( $aAxisType == 'lin' ) {
|
---|
1137 | $this->y2scale = new LinearScale($aY2Min,$aY2Max);
|
---|
1138 | }
|
---|
1139 | elseif( $aAxisType == 'int' ) {
|
---|
1140 | $this->y2scale = new LinearScale($aY2Min,$aY2Max);
|
---|
1141 | $this->y2scale->SetIntScale();
|
---|
1142 | }
|
---|
1143 | elseif( $aAxisType == 'log' ) {
|
---|
1144 | $this->y2scale = new LogScale($aY2Min,$aY2Max);
|
---|
1145 | }
|
---|
1146 | else {
|
---|
1147 | JpGraphError::RaiseL(25023,$aAxisType);//("JpGraph: Unsupported Y2 axis type: $aAxisType\nMust be one of (lin,log,int)");
|
---|
1148 | }
|
---|
1149 |
|
---|
1150 | $this->y2axis = new Axis($this->img,$this->y2scale);
|
---|
1151 | $this->y2axis->scale->ticks->SetDirection(SIDE_LEFT);
|
---|
1152 | $this->y2axis->SetLabelSide(SIDE_RIGHT);
|
---|
1153 | $this->y2axis->SetPos('max');
|
---|
1154 | $this->y2axis->SetTitleSide(SIDE_RIGHT);
|
---|
1155 |
|
---|
1156 | // Deafult position is the max x-value
|
---|
1157 | $this->y2grid = new Grid($this->y2axis);
|
---|
1158 |
|
---|
1159 | if ($this->graph_theme) {
|
---|
1160 | $this->graph_theme->ApplyGraph($this);
|
---|
1161 | }
|
---|
1162 | }
|
---|
1163 |
|
---|
1164 | // Set the delta position (in pixels) between the multiple Y-axis
|
---|
1165 | function SetYDeltaDist($aDist) {
|
---|
1166 | $this->iYAxisDeltaPos = $aDist;
|
---|
1167 | }
|
---|
1168 |
|
---|
1169 | // Specify secondary Y scale
|
---|
1170 | function SetYScale($aN,$aAxisType="lin",$aYMin=1,$aYMax=1) {
|
---|
1171 |
|
---|
1172 | if( $aAxisType == 'lin' ) {
|
---|
1173 | $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax);
|
---|
1174 | }
|
---|
1175 | elseif( $aAxisType == 'int' ) {
|
---|
1176 | $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax);
|
---|
1177 | $this->ynscale[$aN]->SetIntScale();
|
---|
1178 | }
|
---|
1179 | elseif( $aAxisType == 'log' ) {
|
---|
1180 | $this->ynscale[$aN] = new LogScale($aYMin,$aYMax);
|
---|
1181 | }
|
---|
1182 | else {
|
---|
1183 | JpGraphError::RaiseL(25024,$aAxisType);//("JpGraph: Unsupported Y axis type: $aAxisType\nMust be one of (lin,log,int)");
|
---|
1184 | }
|
---|
1185 |
|
---|
1186 | $this->ynaxis[$aN] = new Axis($this->img,$this->ynscale[$aN]);
|
---|
1187 | $this->ynaxis[$aN]->scale->ticks->SetDirection(SIDE_LEFT);
|
---|
1188 | $this->ynaxis[$aN]->SetLabelSide(SIDE_RIGHT);
|
---|
1189 |
|
---|
1190 | if ($this->graph_theme) {
|
---|
1191 | $this->graph_theme->ApplyGraph($this);
|
---|
1192 | }
|
---|
1193 | }
|
---|
1194 |
|
---|
1195 | // Specify density of ticks when autoscaling 'normal', 'dense', 'sparse', 'verysparse'
|
---|
1196 | // The dividing factor have been determined heuristically according to my aesthetic
|
---|
1197 | // sense (or lack off) y.m.m.v !
|
---|
1198 | function SetTickDensity($aYDensity=TICKD_NORMAL,$aXDensity=TICKD_NORMAL) {
|
---|
1199 | $this->xtick_factor=30;
|
---|
1200 | $this->ytick_factor=25;
|
---|
1201 | switch( $aYDensity ) {
|
---|
1202 | case TICKD_DENSE:
|
---|
1203 | $this->ytick_factor=12;
|
---|
1204 | break;
|
---|
1205 | case TICKD_NORMAL:
|
---|
1206 | $this->ytick_factor=25;
|
---|
1207 | break;
|
---|
1208 | case TICKD_SPARSE:
|
---|
1209 | $this->ytick_factor=40;
|
---|
1210 | break;
|
---|
1211 | case TICKD_VERYSPARSE:
|
---|
1212 | $this->ytick_factor=100;
|
---|
1213 | break;
|
---|
1214 | default:
|
---|
1215 | JpGraphError::RaiseL(25025,$densy);//("JpGraph: Unsupported Tick density: $densy");
|
---|
1216 | }
|
---|
1217 | switch( $aXDensity ) {
|
---|
1218 | case TICKD_DENSE:
|
---|
1219 | $this->xtick_factor=15;
|
---|
1220 | break;
|
---|
1221 | case TICKD_NORMAL:
|
---|
1222 | $this->xtick_factor=30;
|
---|
1223 | break;
|
---|
1224 | case TICKD_SPARSE:
|
---|
1225 | $this->xtick_factor=45;
|
---|
1226 | break;
|
---|
1227 | case TICKD_VERYSPARSE:
|
---|
1228 | $this->xtick_factor=60;
|
---|
1229 | break;
|
---|
1230 | default:
|
---|
1231 | JpGraphError::RaiseL(25025,$densx);//("JpGraph: Unsupported Tick density: $densx");
|
---|
1232 | }
|
---|
1233 | }
|
---|
1234 |
|
---|
1235 |
|
---|
1236 | // Get a string of all image map areas
|
---|
1237 | function GetCSIMareas() {
|
---|
1238 | if( !$this->iHasStroked ) {
|
---|
1239 | $this->Stroke(_CSIM_SPECIALFILE);
|
---|
1240 | }
|
---|
1241 |
|
---|
1242 | $csim = $this->title->GetCSIMAreas();
|
---|
1243 | $csim .= $this->subtitle->GetCSIMAreas();
|
---|
1244 | $csim .= $this->subsubtitle->GetCSIMAreas();
|
---|
1245 | $csim .= $this->legend->GetCSIMAreas();
|
---|
1246 |
|
---|
1247 | if( $this->y2axis != NULL ) {
|
---|
1248 | $csim .= $this->y2axis->title->GetCSIMAreas();
|
---|
1249 | }
|
---|
1250 |
|
---|
1251 | if( $this->texts != null ) {
|
---|
1252 | $n = count($this->texts);
|
---|
1253 | for($i=0; $i < $n; ++$i ) {
|
---|
1254 | $csim .= $this->texts[$i]->GetCSIMAreas();
|
---|
1255 | }
|
---|
1256 | }
|
---|
1257 |
|
---|
1258 | if( $this->y2texts != null && $this->y2scale != null ) {
|
---|
1259 | $n = count($this->y2texts);
|
---|
1260 | for($i=0; $i < $n; ++$i ) {
|
---|
1261 | $csim .= $this->y2texts[$i]->GetCSIMAreas();
|
---|
1262 | }
|
---|
1263 | }
|
---|
1264 |
|
---|
1265 | if( $this->yaxis != null && $this->xaxis != null ) {
|
---|
1266 | $csim .= $this->yaxis->title->GetCSIMAreas();
|
---|
1267 | $csim .= $this->xaxis->title->GetCSIMAreas();
|
---|
1268 | }
|
---|
1269 |
|
---|
1270 | $n = count($this->plots);
|
---|
1271 | for( $i=0; $i < $n; ++$i ) {
|
---|
1272 | $csim .= $this->plots[$i]->GetCSIMareas();
|
---|
1273 | }
|
---|
1274 |
|
---|
1275 | $n = count($this->y2plots);
|
---|
1276 | for( $i=0; $i < $n; ++$i ) {
|
---|
1277 | $csim .= $this->y2plots[$i]->GetCSIMareas();
|
---|
1278 | }
|
---|
1279 |
|
---|
1280 | $n = count($this->ynaxis);
|
---|
1281 | for( $i=0; $i < $n; ++$i ) {
|
---|
1282 | $m = count($this->ynplots[$i]);
|
---|
1283 | for($j=0; $j < $m; ++$j ) {
|
---|
1284 | $csim .= $this->ynplots[$i][$j]->GetCSIMareas();
|
---|
1285 | }
|
---|
1286 | }
|
---|
1287 |
|
---|
1288 | if($this->iTables != null) {
|
---|
1289 | $n = count($this->iTables);
|
---|
1290 | for ($i = 0; $i < $n; ++$i) {
|
---|
1291 | $csim .= $this->iTables[$i]->GetCSIMareas();
|
---|
1292 | }
|
---|
1293 | }
|
---|
1294 |
|
---|
1295 | return $csim;
|
---|
1296 | }
|
---|
1297 |
|
---|
1298 | // Get a complete <MAP>..</MAP> tag for the final image map
|
---|
1299 | function GetHTMLImageMap($aMapName) {
|
---|
1300 | $im = "<map name=\"$aMapName\" id=\"$aMapName\" >\n";
|
---|
1301 | $im .= $this->GetCSIMareas();
|
---|
1302 | $im .= "</map>";
|
---|
1303 | return $im;
|
---|
1304 | }
|
---|
1305 |
|
---|
1306 | function CheckCSIMCache($aCacheName,$aTimeOut=60) {
|
---|
1307 | global $_SERVER;
|
---|
1308 |
|
---|
1309 | if( $aCacheName=='auto' ) {
|
---|
1310 | $aCacheName=basename($_SERVER['PHP_SELF']);
|
---|
1311 | }
|
---|
1312 |
|
---|
1313 | $urlarg = $this->GetURLArguments();
|
---|
1314 | $this->csimcachename = CSIMCACHE_DIR.$aCacheName.$urlarg;
|
---|
1315 | $this->csimcachetimeout = $aTimeOut;
|
---|
1316 |
|
---|
1317 | // First determine if we need to check for a cached version
|
---|
1318 | // This differs from the standard cache in the sense that the
|
---|
1319 | // image and CSIM map HTML file is written relative to the directory
|
---|
1320 | // the script executes in and not the specified cache directory.
|
---|
1321 | // The reason for this is that the cache directory is not necessarily
|
---|
1322 | // accessible from the HTTP server.
|
---|
1323 | if( $this->csimcachename != '' ) {
|
---|
1324 | $dir = dirname($this->csimcachename);
|
---|
1325 | $base = basename($this->csimcachename);
|
---|
1326 | $base = strtok($base,'.');
|
---|
1327 | $suffix = strtok('.');
|
---|
1328 | $basecsim = $dir.'/'.$base.'?'.$urlarg.'_csim_.html';
|
---|
1329 | $baseimg = $dir.'/'.$base.'?'.$urlarg.'.'.$this->img->img_format;
|
---|
1330 |
|
---|
1331 | $timedout=false;
|
---|
1332 | // Does it exist at all ?
|
---|
1333 |
|
---|
1334 | if( file_exists($basecsim) && file_exists($baseimg) ) {
|
---|
1335 | // Check that it hasn't timed out
|
---|
1336 | $diff=time()-filemtime($basecsim);
|
---|
1337 | if( $this->csimcachetimeout>0 && ($diff > $this->csimcachetimeout*60) ) {
|
---|
1338 | $timedout=true;
|
---|
1339 | @unlink($basecsim);
|
---|
1340 | @unlink($baseimg);
|
---|
1341 | }
|
---|
1342 | else {
|
---|
1343 | if ($fh = @fopen($basecsim, "r")) {
|
---|
1344 | fpassthru($fh);
|
---|
1345 | return true;
|
---|
1346 | }
|
---|
1347 | else {
|
---|
1348 | JpGraphError::RaiseL(25027,$basecsim);//(" Can't open cached CSIM \"$basecsim\" for reading.");
|
---|
1349 | }
|
---|
1350 | }
|
---|
1351 | }
|
---|
1352 | }
|
---|
1353 | return false;
|
---|
1354 | }
|
---|
1355 |
|
---|
1356 | // Build the argument string to be used with the csim images
|
---|
1357 | static function GetURLArguments($aAddRecursiveBlocker=false) {
|
---|
1358 |
|
---|
1359 | if( $aAddRecursiveBlocker ) {
|
---|
1360 | // This is a JPGRAPH internal defined that prevents
|
---|
1361 | // us from recursively coming here again
|
---|
1362 | $urlarg = _CSIM_DISPLAY.'=1';
|
---|
1363 | }
|
---|
1364 |
|
---|
1365 | // Now reconstruct any user URL argument
|
---|
1366 | reset($_GET);
|
---|
1367 | foreach ($_GET as $key => $value) {
|
---|
1368 | if( is_array($value) ) {
|
---|
1369 | foreach ( $value as $k => $v ) {
|
---|
1370 | $urlarg .= '&'.$key.'%5B'.$k.'%5D='.urlencode($v);
|
---|
1371 | }
|
---|
1372 | }
|
---|
1373 | else {
|
---|
1374 | $urlarg .= '&'.$key.'='.urlencode($value);
|
---|
1375 | }
|
---|
1376 | }
|
---|
1377 |
|
---|
1378 | // It's not ideal to convert POST argument to GET arguments
|
---|
1379 | // but there is little else we can do. One idea for the
|
---|
1380 | // future might be recreate the POST header in case.
|
---|
1381 | reset($_POST);
|
---|
1382 | foreach ($_POST as $key => $value) {
|
---|
1383 | if( is_array($value) ) {
|
---|
1384 | foreach ( $value as $k => $v ) {
|
---|
1385 | $urlarg .= '&'.$key.'%5B'.$k.'%5D='.urlencode($v);
|
---|
1386 | }
|
---|
1387 | }
|
---|
1388 | else {
|
---|
1389 | $urlarg .= '&'.$key.'='.urlencode($value);
|
---|
1390 | }
|
---|
1391 | }
|
---|
1392 |
|
---|
1393 | return $urlarg;
|
---|
1394 | }
|
---|
1395 |
|
---|
1396 | function SetCSIMImgAlt($aAlt) {
|
---|
1397 | $this->iCSIMImgAlt = $aAlt;
|
---|
1398 | }
|
---|
1399 |
|
---|
1400 | function StrokeCSIM($aScriptName='auto',$aCSIMName='',$aBorder=0) {
|
---|
1401 | if( $aCSIMName=='' ) {
|
---|
1402 | // create a random map name
|
---|
1403 | srand ((double) microtime() * 1000000);
|
---|
1404 | $r = rand(0,100000);
|
---|
1405 | $aCSIMName='__mapname'.$r.'__';
|
---|
1406 | }
|
---|
1407 |
|
---|
1408 | if( $aScriptName=='auto' ) {
|
---|
1409 | $aScriptName=basename($_SERVER['PHP_SELF']);
|
---|
1410 | }
|
---|
1411 |
|
---|
1412 | $urlarg = $this->GetURLArguments(true);
|
---|
1413 |
|
---|
1414 | if( empty($_GET[_CSIM_DISPLAY]) ) {
|
---|
1415 | // First determine if we need to check for a cached version
|
---|
1416 | // This differs from the standard cache in the sense that the
|
---|
1417 | // image and CSIM map HTML file is written relative to the directory
|
---|
1418 | // the script executes in and not the specified cache directory.
|
---|
1419 | // The reason for this is that the cache directory is not necessarily
|
---|
1420 | // accessible from the HTTP server.
|
---|
1421 | if( $this->csimcachename != '' ) {
|
---|
1422 | $dir = dirname($this->csimcachename);
|
---|
1423 | $base = basename($this->csimcachename);
|
---|
1424 | $base = strtok($base,'.');
|
---|
1425 | $suffix = strtok('.');
|
---|
1426 | $basecsim = $dir.'/'.$base.'?'.$urlarg.'_csim_.html';
|
---|
1427 | $baseimg = $base.'?'.$urlarg.'.'.$this->img->img_format;
|
---|
1428 |
|
---|
1429 | // Check that apache can write to directory specified
|
---|
1430 |
|
---|
1431 | if( file_exists($dir) && !is_writeable($dir) ) {
|
---|
1432 | JpgraphError::RaiseL(25028,$dir);//('Apache/PHP does not have permission to write to the CSIM cache directory ('.$dir.'). Check permissions.');
|
---|
1433 | }
|
---|
1434 |
|
---|
1435 | // Make sure directory exists
|
---|
1436 | $this->cache->MakeDirs($dir);
|
---|
1437 |
|
---|
1438 | // Write the image file
|
---|
1439 | $this->Stroke(CSIMCACHE_DIR.$baseimg);
|
---|
1440 |
|
---|
1441 | // Construct wrapper HTML and write to file and send it back to browser
|
---|
1442 |
|
---|
1443 | // In the src URL we must replace the '?' with its encoding to prevent the arguments
|
---|
1444 | // to be converted to real arguments.
|
---|
1445 | $tmp = str_replace('?','%3f',$baseimg);
|
---|
1446 | $htmlwrap = $this->GetHTMLImageMap($aCSIMName)."\n".
|
---|
1447 | '<img src="'.CSIMCACHE_HTTP_DIR.$tmp.'" ismap="ismap" usemap="#'.$aCSIMName.' width="'.$this->img->width.'" height="'.$this->img->height."\" alt=\"".$this->iCSIMImgAlt."\" />\n";
|
---|
1448 |
|
---|
1449 | if($fh = @fopen($basecsim,'w') ) {
|
---|
1450 | fwrite($fh,$htmlwrap);
|
---|
1451 | fclose($fh);
|
---|
1452 | echo $htmlwrap;
|
---|
1453 | }
|
---|
1454 | else {
|
---|
1455 | JpGraphError::RaiseL(25029,$basecsim);//(" Can't write CSIM \"$basecsim\" for writing. Check free space and permissions.");
|
---|
1456 | }
|
---|
1457 | }
|
---|
1458 | else {
|
---|
1459 |
|
---|
1460 | if( $aScriptName=='' ) {
|
---|
1461 | JpGraphError::RaiseL(25030);//('Missing script name in call to StrokeCSIM(). You must specify the name of the actual image script as the first parameter to StrokeCSIM().');
|
---|
1462 | }
|
---|
1463 | echo $this->GetHTMLImageMap($aCSIMName) . $this->GetCSIMImgHTML($aCSIMName, $aScriptName, $aBorder);
|
---|
1464 | }
|
---|
1465 | }
|
---|
1466 | else {
|
---|
1467 | $this->Stroke();
|
---|
1468 | }
|
---|
1469 | }
|
---|
1470 |
|
---|
1471 | function StrokeCSIMImage() {
|
---|
1472 | if( @$_GET[_CSIM_DISPLAY] == 1 ) {
|
---|
1473 | $this->Stroke();
|
---|
1474 | }
|
---|
1475 | }
|
---|
1476 |
|
---|
1477 | function GetCSIMImgHTML($aCSIMName, $aScriptName='auto', $aBorder=0 ) {
|
---|
1478 | if( $aScriptName=='auto' ) {
|
---|
1479 | $aScriptName=basename($_SERVER['PHP_SELF']);
|
---|
1480 | }
|
---|
1481 | $urlarg = $this->GetURLArguments(true);
|
---|
1482 | return "<img src=\"".$aScriptName.'?'.$urlarg."\" ismap=\"ismap\" usemap=\"#".$aCSIMName.'" height="'.$this->img->height."\" alt=\"".$this->iCSIMImgAlt."\" />\n";
|
---|
1483 | }
|
---|
1484 |
|
---|
1485 | function GetTextsYMinMax($aY2=false) {
|
---|
1486 | if( $aY2 ) {
|
---|
1487 | $txts = $this->y2texts;
|
---|
1488 | }
|
---|
1489 | else {
|
---|
1490 | $txts = $this->texts;
|
---|
1491 | }
|
---|
1492 | $n = is_array($txts) ? count($txts) : 0;
|
---|
1493 | $min=null;
|
---|
1494 | $max=null;
|
---|
1495 | for( $i=0; $i < $n; ++$i ) {
|
---|
1496 | if( $txts[$i]->iScalePosY !== null && $txts[$i]->iScalePosX !== null ) {
|
---|
1497 | if( $min === null ) {
|
---|
1498 | $min = $max = $txts[$i]->iScalePosY ;
|
---|
1499 | }
|
---|
1500 | else {
|
---|
1501 | $min = min($min,$txts[$i]->iScalePosY);
|
---|
1502 | $max = max($max,$txts[$i]->iScalePosY);
|
---|
1503 | }
|
---|
1504 | }
|
---|
1505 | }
|
---|
1506 | if( $min !== null ) {
|
---|
1507 | return array($min,$max);
|
---|
1508 | }
|
---|
1509 | else {
|
---|
1510 | return null;
|
---|
1511 | }
|
---|
1512 | }
|
---|
1513 |
|
---|
1514 | function GetTextsXMinMax($aY2=false) {
|
---|
1515 | if( $aY2 ) {
|
---|
1516 | $txts = $this->y2texts;
|
---|
1517 | }
|
---|
1518 | else {
|
---|
1519 | $txts = $this->texts;
|
---|
1520 | }
|
---|
1521 | $n = is_array($txts) ? count($txts) : 0;
|
---|
1522 | $min=null;
|
---|
1523 | $max=null;
|
---|
1524 | for( $i=0; $i < $n; ++$i ) {
|
---|
1525 | if( $txts[$i]->iScalePosY !== null && $txts[$i]->iScalePosX !== null ) {
|
---|
1526 | if( $min === null ) {
|
---|
1527 | $min = $max = $txts[$i]->iScalePosX ;
|
---|
1528 | }
|
---|
1529 | else {
|
---|
1530 | $min = min($min,$txts[$i]->iScalePosX);
|
---|
1531 | $max = max($max,$txts[$i]->iScalePosX);
|
---|
1532 | }
|
---|
1533 | }
|
---|
1534 | }
|
---|
1535 | if( $min !== null ) {
|
---|
1536 | return array($min,$max);
|
---|
1537 | }
|
---|
1538 | else {
|
---|
1539 | return null;
|
---|
1540 | }
|
---|
1541 | }
|
---|
1542 |
|
---|
1543 | function GetXMinMax() {
|
---|
1544 |
|
---|
1545 | list($min,$ymin) = $this->plots[0]->Min();
|
---|
1546 | list($max,$ymax) = $this->plots[0]->Max();
|
---|
1547 |
|
---|
1548 | $i=0;
|
---|
1549 | // Some plots, e.g. PlotLine should not affect the scale
|
---|
1550 | // and will return (null,null). We should ignore those
|
---|
1551 | // values.
|
---|
1552 | while( ($min===null || $max === null) && ($i < count($this->plots)-1) ) {
|
---|
1553 | ++$i;
|
---|
1554 | list($min,$ymin) = $this->plots[$i]->Min();
|
---|
1555 | list($max,$ymax) = $this->plots[$i]->Max();
|
---|
1556 | }
|
---|
1557 |
|
---|
1558 | foreach( $this->plots as $p ) {
|
---|
1559 | list($xmin,$ymin) = $p->Min();
|
---|
1560 | list($xmax,$ymax) = $p->Max();
|
---|
1561 |
|
---|
1562 | if( $xmin !== null && $xmax !== null ) {
|
---|
1563 | $min = Min($xmin,$min);
|
---|
1564 | $max = Max($xmax,$max);
|
---|
1565 | }
|
---|
1566 | }
|
---|
1567 |
|
---|
1568 | if( $this->y2axis != null ) {
|
---|
1569 | foreach( $this->y2plots as $p ) {
|
---|
1570 | list($xmin,$ymin) = $p->Min();
|
---|
1571 | list($xmax,$ymax) = $p->Max();
|
---|
1572 | if( $xmin !== null && $xmax !== null ) {
|
---|
1573 | $min = Min($xmin, $min);
|
---|
1574 | $max = Max($xmax, $max);
|
---|
1575 | }
|
---|
1576 | }
|
---|
1577 | }
|
---|
1578 |
|
---|
1579 | $n = count($this->ynaxis);
|
---|
1580 | for( $i=0; $i < $n; ++$i ) {
|
---|
1581 | if( $this->ynaxis[$i] != null) {
|
---|
1582 | foreach( $this->ynplots[$i] as $p ) {
|
---|
1583 | list($xmin,$ymin) = $p->Min();
|
---|
1584 | list($xmax,$ymax) = $p->Max();
|
---|
1585 | if( $xmin !== null && $xmax !== null ) {
|
---|
1586 | $min = Min($xmin, $min);
|
---|
1587 | $max = Max($xmax, $max);
|
---|
1588 | }
|
---|
1589 | }
|
---|
1590 | }
|
---|
1591 | }
|
---|
1592 | return array($min,$max);
|
---|
1593 | }
|
---|
1594 |
|
---|
1595 | function AdjustMarginsForTitles() {
|
---|
1596 | $totrequired =
|
---|
1597 | ($this->title->t != ''
|
---|
1598 | ? $this->title->GetTextHeight($this->img) + $this->title->margin + 5 * SUPERSAMPLING_SCALE
|
---|
1599 | : 0 ) +
|
---|
1600 | ($this->subtitle->t != ''
|
---|
1601 | ? $this->subtitle->GetTextHeight($this->img) + $this->subtitle->margin + 5 * SUPERSAMPLING_SCALE
|
---|
1602 | : 0 ) +
|
---|
1603 | ($this->subsubtitle->t != ''
|
---|
1604 | ? $this->subsubtitle->GetTextHeight($this->img) + $this->subsubtitle->margin + 5 * SUPERSAMPLING_SCALE
|
---|
1605 | : 0 ) ;
|
---|
1606 |
|
---|
1607 | $btotrequired = 0;
|
---|
1608 | if($this->xaxis != null && !$this->xaxis->hide && !$this->xaxis->hide_labels ) {
|
---|
1609 | // Minimum bottom margin
|
---|
1610 | if( $this->xaxis->title->t != '' ) {
|
---|
1611 | if( $this->img->a == 90 ) {
|
---|
1612 | $btotrequired = $this->yaxis->title->GetTextHeight($this->img) + 7 ;
|
---|
1613 | }
|
---|
1614 | else {
|
---|
1615 | $btotrequired = $this->xaxis->title->GetTextHeight($this->img) + 7 ;
|
---|
1616 | }
|
---|
1617 | }
|
---|
1618 | else {
|
---|
1619 | $btotrequired = 0;
|
---|
1620 | }
|
---|
1621 |
|
---|
1622 | if( $this->img->a == 90 ) {
|
---|
1623 | $this->img->SetFont($this->yaxis->font_family,$this->yaxis->font_style,
|
---|
1624 | $this->yaxis->font_size);
|
---|
1625 | $lh = $this->img->GetTextHeight('Mg',$this->yaxis->label_angle);
|
---|
1626 | }
|
---|
1627 | else {
|
---|
1628 | $this->img->SetFont($this->xaxis->font_family,$this->xaxis->font_style,
|
---|
1629 | $this->xaxis->font_size);
|
---|
1630 | $lh = $this->img->GetTextHeight('Mg',$this->xaxis->label_angle);
|
---|
1631 | }
|
---|
1632 |
|
---|
1633 | $btotrequired += $lh + 6;
|
---|
1634 | }
|
---|
1635 |
|
---|
1636 | if( $this->img->a == 90 ) {
|
---|
1637 | // DO Nothing. It gets too messy to do this properly for 90 deg...
|
---|
1638 | }
|
---|
1639 | else{
|
---|
1640 | // need more top margin
|
---|
1641 | if( $this->img->top_margin < $totrequired ) {
|
---|
1642 | $this->SetMargin(
|
---|
1643 | $this->img->raw_left_margin,
|
---|
1644 | $this->img->raw_right_margin,
|
---|
1645 | $totrequired / SUPERSAMPLING_SCALE,
|
---|
1646 | $this->img->raw_bottom_margin
|
---|
1647 | );
|
---|
1648 | }
|
---|
1649 |
|
---|
1650 | // need more bottom margin
|
---|
1651 | if( $this->img->bottom_margin < $btotrequired ) {
|
---|
1652 | $this->SetMargin(
|
---|
1653 | $this->img->raw_left_margin,
|
---|
1654 | $this->img->raw_right_margin,
|
---|
1655 | $this->img->raw_top_margin,
|
---|
1656 | $btotrequired / SUPERSAMPLING_SCALE
|
---|
1657 | );
|
---|
1658 | }
|
---|
1659 | }
|
---|
1660 | }
|
---|
1661 |
|
---|
1662 | function StrokeStore($aStrokeFileName) {
|
---|
1663 | // Get the handler to prevent the library from sending the
|
---|
1664 | // image to the browser
|
---|
1665 | $ih = $this->Stroke(_IMG_HANDLER);
|
---|
1666 |
|
---|
1667 | // Stroke it to a file
|
---|
1668 | $this->img->Stream($aStrokeFileName);
|
---|
1669 |
|
---|
1670 | // Send it back to browser
|
---|
1671 | $this->img->Headers();
|
---|
1672 | $this->img->Stream();
|
---|
1673 | }
|
---|
1674 |
|
---|
1675 | function doAutoscaleXAxis() {
|
---|
1676 | //Check if we should autoscale x-axis
|
---|
1677 | if( !$this->xscale->IsSpecified() ) {
|
---|
1678 | if( substr($this->axtype,0,4) == "text" ) {
|
---|
1679 | $max=0;
|
---|
1680 | $n = count($this->plots);
|
---|
1681 | for($i=0; $i < $n; ++$i ) {
|
---|
1682 | $p = $this->plots[$i];
|
---|
1683 | // We need some unfortunate sub class knowledge here in order
|
---|
1684 | // to increase number of data points in case it is a line plot
|
---|
1685 | // which has the barcenter set. If not it could mean that the
|
---|
1686 | // last point of the data is outside the scale since the barcenter
|
---|
1687 | // settings means that we will shift the entire plot half a tick step
|
---|
1688 | // to the right in oder to align with the center of the bars.
|
---|
1689 | if( class_exists('BarPlot',false) ) {
|
---|
1690 | $cl = strtolower(get_class($p));
|
---|
1691 | if( (class_exists('BarPlot',false) && ($p instanceof BarPlot)) || empty($p->barcenter) ) {
|
---|
1692 | $max=max($max,$p->numpoints-1);
|
---|
1693 | }
|
---|
1694 | else {
|
---|
1695 | $max=max($max,$p->numpoints);
|
---|
1696 | }
|
---|
1697 | }
|
---|
1698 | else {
|
---|
1699 | if( empty($p->barcenter) ) {
|
---|
1700 | $max=max($max,$p->numpoints-1);
|
---|
1701 | }
|
---|
1702 | else {
|
---|
1703 | $max=max($max,$p->numpoints);
|
---|
1704 | }
|
---|
1705 | }
|
---|
1706 | }
|
---|
1707 | $min=0;
|
---|
1708 | if( $this->y2axis != null ) {
|
---|
1709 | foreach( $this->y2plots as $p ) {
|
---|
1710 | $max=max($max,$p->numpoints-1);
|
---|
1711 | }
|
---|
1712 | }
|
---|
1713 | $n = count($this->ynaxis);
|
---|
1714 | for( $i=0; $i < $n; ++$i ) {
|
---|
1715 | if( $this->ynaxis[$i] != null) {
|
---|
1716 | foreach( $this->ynplots[$i] as $p ) {
|
---|
1717 | $max=max($max,$p->numpoints-1);
|
---|
1718 | }
|
---|
1719 | }
|
---|
1720 | }
|
---|
1721 |
|
---|
1722 | $this->xscale->Update($this->img,$min,$max);
|
---|
1723 | $this->xscale->ticks->Set($this->xaxis->tick_step,1);
|
---|
1724 | $this->xscale->ticks->SupressMinorTickMarks();
|
---|
1725 | }
|
---|
1726 | else {
|
---|
1727 | list($min,$max) = $this->GetXMinMax();
|
---|
1728 |
|
---|
1729 | $lres = $this->GetLinesXMinMax($this->lines);
|
---|
1730 | if( $lres ) {
|
---|
1731 | list($linmin,$linmax) = $lres ;
|
---|
1732 | $min = min($min,$linmin);
|
---|
1733 | $max = max($max,$linmax);
|
---|
1734 | }
|
---|
1735 |
|
---|
1736 | $lres = $this->GetLinesXMinMax($this->y2lines);
|
---|
1737 | if( $lres ) {
|
---|
1738 | list($linmin,$linmax) = $lres ;
|
---|
1739 | $min = min($min,$linmin);
|
---|
1740 | $max = max($max,$linmax);
|
---|
1741 | }
|
---|
1742 |
|
---|
1743 | $tres = $this->GetTextsXMinMax();
|
---|
1744 | if( $tres ) {
|
---|
1745 | list($tmin,$tmax) = $tres ;
|
---|
1746 | $min = min($min,$tmin);
|
---|
1747 | $max = max($max,$tmax);
|
---|
1748 | }
|
---|
1749 |
|
---|
1750 | $tres = $this->GetTextsXMinMax(true);
|
---|
1751 | if( $tres ) {
|
---|
1752 | list($tmin,$tmax) = $tres ;
|
---|
1753 | $min = min($min,$tmin);
|
---|
1754 | $max = max($max,$tmax);
|
---|
1755 | }
|
---|
1756 |
|
---|
1757 | $this->xscale->AutoScale($this->img,$min,$max,round($this->img->plotwidth/$this->xtick_factor));
|
---|
1758 | }
|
---|
1759 |
|
---|
1760 | //Adjust position of y-axis and y2-axis to minimum/maximum of x-scale
|
---|
1761 | if( !is_numeric($this->yaxis->pos) && !is_string($this->yaxis->pos) ) {
|
---|
1762 | $this->yaxis->SetPos($this->xscale->GetMinVal());
|
---|
1763 | }
|
---|
1764 | }
|
---|
1765 | elseif( $this->xscale->IsSpecified() &&
|
---|
1766 | ( $this->xscale->auto_ticks || !$this->xscale->ticks->IsSpecified()) ) {
|
---|
1767 | // The tick calculation will use the user suplied min/max values to determine
|
---|
1768 | // the ticks. If auto_ticks is false the exact user specifed min and max
|
---|
1769 | // values will be used for the scale.
|
---|
1770 | // If auto_ticks is true then the scale might be slightly adjusted
|
---|
1771 | // so that the min and max values falls on an even major step.
|
---|
1772 | $min = $this->xscale->scale[0];
|
---|
1773 | $max = $this->xscale->scale[1];
|
---|
1774 | $this->xscale->AutoScale($this->img,$min,$max,round($this->img->plotwidth/$this->xtick_factor),false);
|
---|
1775 |
|
---|
1776 | // Now make sure we show enough precision to accurate display the
|
---|
1777 | // labels. If this is not done then the user might end up with
|
---|
1778 | // a scale that might actually start with, say 13.5, butdue to rounding
|
---|
1779 | // the scale label will ony show 14.
|
---|
1780 | if( abs(floor($min)-$min) > 0 ) {
|
---|
1781 |
|
---|
1782 | // If the user has set a format then we bail out
|
---|
1783 | if( $this->xscale->ticks->label_formatstr == '' && $this->xscale->ticks->label_dateformatstr == '' ) {
|
---|
1784 | $this->xscale->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1;
|
---|
1785 | }
|
---|
1786 | }
|
---|
1787 | }
|
---|
1788 |
|
---|
1789 | // Position the optional Y2 and Yn axis to the rightmost position of the x-axis
|
---|
1790 | if( $this->y2axis != null ) {
|
---|
1791 | if( !is_numeric($this->y2axis->pos) && !is_string($this->y2axis->pos) ) {
|
---|
1792 | $this->y2axis->SetPos($this->xscale->GetMaxVal());
|
---|
1793 | }
|
---|
1794 | $this->y2axis->SetTitleSide(SIDE_RIGHT);
|
---|
1795 | }
|
---|
1796 |
|
---|
1797 | $n = count($this->ynaxis);
|
---|
1798 | $nY2adj = $this->y2axis != null ? $this->iYAxisDeltaPos : 0;
|
---|
1799 | for( $i=0; $i < $n; ++$i ) {
|
---|
1800 | if( $this->ynaxis[$i] != null ) {
|
---|
1801 | if( !is_numeric($this->ynaxis[$i]->pos) && !is_string($this->ynaxis[$i]->pos) ) {
|
---|
1802 | $this->ynaxis[$i]->SetPos($this->xscale->GetMaxVal());
|
---|
1803 | $this->ynaxis[$i]->SetPosAbsDelta($i*$this->iYAxisDeltaPos + $nY2adj);
|
---|
1804 | }
|
---|
1805 | $this->ynaxis[$i]->SetTitleSide(SIDE_RIGHT);
|
---|
1806 | }
|
---|
1807 | }
|
---|
1808 | }
|
---|
1809 |
|
---|
1810 |
|
---|
1811 | function doAutoScaleYnAxis() {
|
---|
1812 |
|
---|
1813 | if( $this->y2scale != null) {
|
---|
1814 | if( !$this->y2scale->IsSpecified() && count($this->y2plots)>0 ) {
|
---|
1815 | list($min,$max) = $this->GetPlotsYMinMax($this->y2plots);
|
---|
1816 |
|
---|
1817 | $lres = $this->GetLinesYMinMax($this->y2lines);
|
---|
1818 | if( is_array($lres) ) {
|
---|
1819 | list($linmin,$linmax) = $lres ;
|
---|
1820 | $min = min($min,$linmin);
|
---|
1821 | $max = max($max,$linmax);
|
---|
1822 | }
|
---|
1823 | $tres = $this->GetTextsYMinMax(true);
|
---|
1824 | if( is_array($tres) ) {
|
---|
1825 | list($tmin,$tmax) = $tres ;
|
---|
1826 | $min = min($min,$tmin);
|
---|
1827 | $max = max($max,$tmax);
|
---|
1828 | }
|
---|
1829 | $this->y2scale->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor);
|
---|
1830 | }
|
---|
1831 | elseif( $this->y2scale->IsSpecified() && ( $this->y2scale->auto_ticks || !$this->y2scale->ticks->IsSpecified()) ) {
|
---|
1832 | // The tick calculation will use the user suplied min/max values to determine
|
---|
1833 | // the ticks. If auto_ticks is false the exact user specifed min and max
|
---|
1834 | // values will be used for the scale.
|
---|
1835 | // If auto_ticks is true then the scale might be slightly adjusted
|
---|
1836 | // so that the min and max values falls on an even major step.
|
---|
1837 | $min = $this->y2scale->scale[0];
|
---|
1838 | $max = $this->y2scale->scale[1];
|
---|
1839 | $this->y2scale->AutoScale($this->img,$min,$max,
|
---|
1840 | $this->img->plotheight/$this->ytick_factor,
|
---|
1841 | $this->y2scale->auto_ticks);
|
---|
1842 |
|
---|
1843 | // Now make sure we show enough precision to accurate display the
|
---|
1844 | // labels. If this is not done then the user might end up with
|
---|
1845 | // a scale that might actually start with, say 13.5, butdue to rounding
|
---|
1846 | // the scale label will ony show 14.
|
---|
1847 | if( abs(floor($min)-$min) > 0 ) {
|
---|
1848 | // If the user has set a format then we bail out
|
---|
1849 | if( $this->y2scale->ticks->label_formatstr == '' && $this->y2scale->ticks->label_dateformatstr == '' ) {
|
---|
1850 | $this->y2scale->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1;
|
---|
1851 | }
|
---|
1852 | }
|
---|
1853 |
|
---|
1854 | }
|
---|
1855 | }
|
---|
1856 |
|
---|
1857 |
|
---|
1858 | //
|
---|
1859 | // Autoscale the extra Y-axises
|
---|
1860 | //
|
---|
1861 | $n = count($this->ynaxis);
|
---|
1862 | for( $i=0; $i < $n; ++$i ) {
|
---|
1863 | if( $this->ynscale[$i] != null) {
|
---|
1864 | if( !$this->ynscale[$i]->IsSpecified() && count($this->ynplots[$i])>0 ) {
|
---|
1865 | list($min,$max) = $this->GetPlotsYMinMax($this->ynplots[$i]);
|
---|
1866 | $this->ynscale[$i]->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor);
|
---|
1867 | }
|
---|
1868 | elseif( $this->ynscale[$i]->IsSpecified() && ( $this->ynscale[$i]->auto_ticks || !$this->ynscale[$i]->ticks->IsSpecified()) ) {
|
---|
1869 | // The tick calculation will use the user suplied min/max values to determine
|
---|
1870 | // the ticks. If auto_ticks is false the exact user specifed min and max
|
---|
1871 | // values will be used for the scale.
|
---|
1872 | // If auto_ticks is true then the scale might be slightly adjusted
|
---|
1873 | // so that the min and max values falls on an even major step.
|
---|
1874 | $min = $this->ynscale[$i]->scale[0];
|
---|
1875 | $max = $this->ynscale[$i]->scale[1];
|
---|
1876 | $this->ynscale[$i]->AutoScale($this->img,$min,$max,
|
---|
1877 | $this->img->plotheight/$this->ytick_factor,
|
---|
1878 | $this->ynscale[$i]->auto_ticks);
|
---|
1879 |
|
---|
1880 | // Now make sure we show enough precision to accurate display the
|
---|
1881 | // labels. If this is not done then the user might end up with
|
---|
1882 | // a scale that might actually start with, say 13.5, butdue to rounding
|
---|
1883 | // the scale label will ony show 14.
|
---|
1884 | if( abs(floor($min)-$min) > 0 ) {
|
---|
1885 | // If the user has set a format then we bail out
|
---|
1886 | if( $this->ynscale[$i]->ticks->label_formatstr == '' && $this->ynscale[$i]->ticks->label_dateformatstr == '' ) {
|
---|
1887 | $this->ynscale[$i]->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1;
|
---|
1888 | }
|
---|
1889 | }
|
---|
1890 | }
|
---|
1891 | }
|
---|
1892 | }
|
---|
1893 | }
|
---|
1894 |
|
---|
1895 | function doAutoScaleYAxis() {
|
---|
1896 |
|
---|
1897 | //Check if we should autoscale y-axis
|
---|
1898 | if( !$this->yscale->IsSpecified() && count($this->plots)>0 ) {
|
---|
1899 | list($min,$max) = $this->GetPlotsYMinMax($this->plots);
|
---|
1900 | $lres = $this->GetLinesYMinMax($this->lines);
|
---|
1901 | if( is_array($lres) ) {
|
---|
1902 | list($linmin,$linmax) = $lres ;
|
---|
1903 | $min = min($min,$linmin);
|
---|
1904 | $max = max($max,$linmax);
|
---|
1905 | }
|
---|
1906 | $tres = $this->GetTextsYMinMax();
|
---|
1907 | if( is_array($tres) ) {
|
---|
1908 | list($tmin,$tmax) = $tres ;
|
---|
1909 | $min = min($min,$tmin);
|
---|
1910 | $max = max($max,$tmax);
|
---|
1911 | }
|
---|
1912 | $this->yscale->AutoScale($this->img,$min,$max,
|
---|
1913 | $this->img->plotheight/$this->ytick_factor);
|
---|
1914 | }
|
---|
1915 | elseif( $this->yscale->IsSpecified() && ( $this->yscale->auto_ticks || !$this->yscale->ticks->IsSpecified()) ) {
|
---|
1916 | // The tick calculation will use the user suplied min/max values to determine
|
---|
1917 | // the ticks. If auto_ticks is false the exact user specifed min and max
|
---|
1918 | // values will be used for the scale.
|
---|
1919 | // If auto_ticks is true then the scale might be slightly adjusted
|
---|
1920 | // so that the min and max values falls on an even major step.
|
---|
1921 | $min = $this->yscale->scale[0];
|
---|
1922 | $max = $this->yscale->scale[1];
|
---|
1923 | $this->yscale->AutoScale($this->img,$min,$max,
|
---|
1924 | $this->img->plotheight/$this->ytick_factor,
|
---|
1925 | $this->yscale->auto_ticks);
|
---|
1926 |
|
---|
1927 | // Now make sure we show enough precision to accurate display the
|
---|
1928 | // labels. If this is not done then the user might end up with
|
---|
1929 | // a scale that might actually start with, say 13.5, butdue to rounding
|
---|
1930 | // the scale label will ony show 14.
|
---|
1931 | if( abs(floor($min)-$min) > 0 ) {
|
---|
1932 |
|
---|
1933 | // If the user has set a format then we bail out
|
---|
1934 | if( $this->yscale->ticks->label_formatstr == '' && $this->yscale->ticks->label_dateformatstr == '' ) {
|
---|
1935 | $this->yscale->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1;
|
---|
1936 | }
|
---|
1937 | }
|
---|
1938 | }
|
---|
1939 |
|
---|
1940 | }
|
---|
1941 |
|
---|
1942 | function InitScaleConstants() {
|
---|
1943 | // Setup scale constants
|
---|
1944 | if( $this->yscale ) $this->yscale->InitConstants($this->img);
|
---|
1945 | if( $this->xscale ) $this->xscale->InitConstants($this->img);
|
---|
1946 | if( $this->y2scale ) $this->y2scale->InitConstants($this->img);
|
---|
1947 |
|
---|
1948 | $n=count($this->ynscale);
|
---|
1949 | for($i=0; $i < $n; ++$i) {
|
---|
1950 | if( $this->ynscale[$i] ) {
|
---|
1951 | $this->ynscale[$i]->InitConstants($this->img);
|
---|
1952 | }
|
---|
1953 | }
|
---|
1954 | }
|
---|
1955 |
|
---|
1956 | function doPrestrokeAdjustments() {
|
---|
1957 |
|
---|
1958 | // Do any pre-stroke adjustment that is needed by the different plot types
|
---|
1959 | // (i.e bar plots want's to add an offset to the x-labels etc)
|
---|
1960 | for($i=0; $i < count($this->plots) ; ++$i ) {
|
---|
1961 | $this->plots[$i]->PreStrokeAdjust($this);
|
---|
1962 | $this->plots[$i]->DoLegend($this);
|
---|
1963 | }
|
---|
1964 |
|
---|
1965 | // Any plots on the second Y scale?
|
---|
1966 | if( $this->y2scale != null ) {
|
---|
1967 | for($i=0; $i<count($this->y2plots) ; ++$i ) {
|
---|
1968 | $this->y2plots[$i]->PreStrokeAdjust($this);
|
---|
1969 | $this->y2plots[$i]->DoLegend($this);
|
---|
1970 | }
|
---|
1971 | }
|
---|
1972 |
|
---|
1973 | // Any plots on the extra Y axises?
|
---|
1974 | $n = count($this->ynaxis);
|
---|
1975 | for($i=0; $i<$n ; ++$i ) {
|
---|
1976 | if( $this->ynplots == null || $this->ynplots[$i] == null) {
|
---|
1977 | JpGraphError::RaiseL(25032,$i);//("No plots for Y-axis nbr:$i");
|
---|
1978 | }
|
---|
1979 | $m = count($this->ynplots[$i]);
|
---|
1980 | for($j=0; $j < $m; ++$j ) {
|
---|
1981 | $this->ynplots[$i][$j]->PreStrokeAdjust($this);
|
---|
1982 | $this->ynplots[$i][$j]->DoLegend($this);
|
---|
1983 | }
|
---|
1984 | }
|
---|
1985 | }
|
---|
1986 |
|
---|
1987 | function StrokeBands($aDepth,$aCSIM) {
|
---|
1988 | // Stroke bands
|
---|
1989 | if( $this->bands != null && !$aCSIM) {
|
---|
1990 | for($i=0; $i < count($this->bands); ++$i) {
|
---|
1991 | // Stroke all bands that asks to be in the background
|
---|
1992 | if( $this->bands[$i]->depth == $aDepth ) {
|
---|
1993 | $this->bands[$i]->Stroke($this->img,$this->xscale,$this->yscale);
|
---|
1994 | }
|
---|
1995 | }
|
---|
1996 | }
|
---|
1997 |
|
---|
1998 | if( $this->y2bands != null && $this->y2scale != null && !$aCSIM ) {
|
---|
1999 | for($i=0; $i < count($this->y2bands); ++$i) {
|
---|
2000 | // Stroke all bands that asks to be in the foreground
|
---|
2001 | if( $this->y2bands[$i]->depth == $aDepth ) {
|
---|
2002 | $this->y2bands[$i]->Stroke($this->img,$this->xscale,$this->y2scale);
|
---|
2003 | }
|
---|
2004 | }
|
---|
2005 | }
|
---|
2006 | }
|
---|
2007 |
|
---|
2008 |
|
---|
2009 | // Stroke the graph
|
---|
2010 | // $aStrokeFileName If != "" the image will be written to this file and NOT
|
---|
2011 | // streamed back to the browser
|
---|
2012 | function Stroke($aStrokeFileName='') {
|
---|
2013 | // Fist make a sanity check that user has specified a scale
|
---|
2014 | if( empty($this->yscale) ) {
|
---|
2015 | JpGraphError::RaiseL(25031);//('You must specify what scale to use with a call to Graph::SetScale().');
|
---|
2016 | }
|
---|
2017 |
|
---|
2018 | // Start by adjusting the margin so that potential titles will fit.
|
---|
2019 | $this->AdjustMarginsForTitles();
|
---|
2020 |
|
---|
2021 | // Give the plot a chance to do any scale adjuments the individual plots
|
---|
2022 | // wants to do. Right now this is only used by the contour plot to set scale
|
---|
2023 | // limits
|
---|
2024 | for($i=0; $i < count($this->plots) ; ++$i ) {
|
---|
2025 | $this->plots[$i]->PreScaleSetup($this);
|
---|
2026 | }
|
---|
2027 |
|
---|
2028 | // Init scale constants that are used to calculate the transformation from
|
---|
2029 | // world to pixel coordinates
|
---|
2030 | $this->InitScaleConstants();
|
---|
2031 |
|
---|
2032 | // If the filename is the predefined value = '_csim_special_'
|
---|
2033 | // we assume that the call to stroke only needs to do enough
|
---|
2034 | // to correctly generate the CSIM maps.
|
---|
2035 | // We use this variable to skip things we don't strictly need
|
---|
2036 | // to do to generate the image map to improve performance
|
---|
2037 | // a best we can. Therefor you will see a lot of tests !$_csim in the
|
---|
2038 | // code below.
|
---|
2039 | $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE);
|
---|
2040 |
|
---|
2041 | // If we are called the second time (perhaps the user has called GetHTMLImageMap()
|
---|
2042 | // himself then the legends have alsready been populated once in order to get the
|
---|
2043 | // CSIM coordinats. Since we do not want the legends to be populated a second time
|
---|
2044 | // we clear the legends
|
---|
2045 | $this->legend->Clear();
|
---|
2046 |
|
---|
2047 | // We need to know if we have stroked the plot in the
|
---|
2048 | // GetCSIMareas. Otherwise the CSIM hasn't been generated
|
---|
2049 | // and in the case of GetCSIM called before stroke to generate
|
---|
2050 | // CSIM without storing an image to disk GetCSIM must call Stroke.
|
---|
2051 | $this->iHasStroked = true;
|
---|
2052 |
|
---|
2053 | // Setup pre-stroked adjustments and Legends
|
---|
2054 | $this->doPrestrokeAdjustments();
|
---|
2055 |
|
---|
2056 | if ($this->graph_theme) {
|
---|
2057 | $this->graph_theme->PreStrokeApply($this);
|
---|
2058 | }
|
---|
2059 |
|
---|
2060 | // Bail out if any of the Y-axis not been specified and
|
---|
2061 | // has no plots. (This means it is impossible to do autoscaling and
|
---|
2062 | // no other scale was given so we can't possible draw anything). If you use manual
|
---|
2063 | // scaling you also have to supply the tick steps as well.
|
---|
2064 | if( (!$this->yscale->IsSpecified() && count($this->plots)==0) ||
|
---|
2065 | ($this->y2scale!=null && !$this->y2scale->IsSpecified() && count($this->y2plots)==0) ) {
|
---|
2066 | //$e = "n=".count($this->y2plots)."\n";
|
---|
2067 | // $e = "Can't draw unspecified Y-scale.<br>\nYou have either:<br>\n";
|
---|
2068 | // $e .= "1. Specified an Y axis for autoscaling but have not supplied any plots<br>\n";
|
---|
2069 | // $e .= "2. Specified a scale manually but have forgot to specify the tick steps";
|
---|
2070 | JpGraphError::RaiseL(25026);
|
---|
2071 | }
|
---|
2072 |
|
---|
2073 | // Bail out if no plots and no specified X-scale
|
---|
2074 | if( (!$this->xscale->IsSpecified() && count($this->plots)==0 && count($this->y2plots)==0) ) {
|
---|
2075 | JpGraphError::RaiseL(25034);//("<strong>JpGraph: Can't draw unspecified X-scale.</strong><br>No plots.<br>");
|
---|
2076 | }
|
---|
2077 |
|
---|
2078 | // Autoscale the normal Y-axis
|
---|
2079 | $this->doAutoScaleYAxis();
|
---|
2080 |
|
---|
2081 | // Autoscale all additiopnal y-axis
|
---|
2082 | $this->doAutoScaleYnAxis();
|
---|
2083 |
|
---|
2084 | // Autoscale the regular x-axis and position the y-axis properly
|
---|
2085 | $this->doAutoScaleXAxis();
|
---|
2086 |
|
---|
2087 | // If we have a negative values and x-axis position is at 0
|
---|
2088 | // we need to supress the first and possible the last tick since
|
---|
2089 | // they will be drawn on top of the y-axis (and possible y2 axis)
|
---|
2090 | // The test below might seem strange the reasone being that if
|
---|
2091 | // the user hasn't specified a value for position this will not
|
---|
2092 | // be set until we do the stroke for the axis so as of now it
|
---|
2093 | // is undefined.
|
---|
2094 | // For X-text scale we ignore all this since the tick are usually
|
---|
2095 | // much further in and not close to the Y-axis. Hence the test
|
---|
2096 | // for 'text'
|
---|
2097 | if( ($this->yaxis->pos==$this->xscale->GetMinVal() || (is_string($this->yaxis->pos) && $this->yaxis->pos=='min')) &&
|
---|
2098 | !is_numeric($this->xaxis->pos) && $this->yscale->GetMinVal() < 0 &&
|
---|
2099 | substr($this->axtype,0,4) != 'text' && $this->xaxis->pos != 'min' ) {
|
---|
2100 |
|
---|
2101 | //$this->yscale->ticks->SupressZeroLabel(false);
|
---|
2102 | $this->xscale->ticks->SupressFirst();
|
---|
2103 | if( $this->y2axis != null ) {
|
---|
2104 | $this->xscale->ticks->SupressLast();
|
---|
2105 | }
|
---|
2106 | }
|
---|
2107 | elseif( !is_numeric($this->yaxis->pos) && $this->yaxis->pos=='max' ) {
|
---|
2108 | $this->xscale->ticks->SupressLast();
|
---|
2109 | }
|
---|
2110 |
|
---|
2111 | if( !$_csim ) {
|
---|
2112 | $this->StrokePlotArea();
|
---|
2113 | if( $this->iIconDepth == DEPTH_BACK ) {
|
---|
2114 | $this->StrokeIcons();
|
---|
2115 | }
|
---|
2116 | }
|
---|
2117 | $this->StrokeAxis(false);
|
---|
2118 |
|
---|
2119 | // Stroke colored bands
|
---|
2120 | $this->StrokeBands(DEPTH_BACK,$_csim);
|
---|
2121 |
|
---|
2122 | if( $this->grid_depth == DEPTH_BACK && !$_csim) {
|
---|
2123 | $this->ygrid->Stroke();
|
---|
2124 | $this->xgrid->Stroke();
|
---|
2125 | }
|
---|
2126 |
|
---|
2127 | // Stroke Y2-axis
|
---|
2128 | if( $this->y2axis != null && !$_csim) {
|
---|
2129 | $this->y2axis->Stroke($this->xscale);
|
---|
2130 | $this->y2grid->Stroke();
|
---|
2131 | }
|
---|
2132 |
|
---|
2133 | // Stroke yn-axis
|
---|
2134 | $n = count($this->ynaxis);
|
---|
2135 | for( $i=0; $i < $n; ++$i ) {
|
---|
2136 | $this->ynaxis[$i]->Stroke($this->xscale);
|
---|
2137 | }
|
---|
2138 |
|
---|
2139 | $oldoff=$this->xscale->off;
|
---|
2140 | if( substr($this->axtype,0,4) == 'text' ) {
|
---|
2141 | if( $this->text_scale_abscenteroff > -1 ) {
|
---|
2142 | // For a text scale the scale factor is the number of pixel per step.
|
---|
2143 | // Hence we can use the scale factor as a substitute for number of pixels
|
---|
2144 | // per major scale step and use that in order to adjust the offset so that
|
---|
2145 | // an object of width "abscenteroff" becomes centered.
|
---|
2146 | $this->xscale->off += round($this->xscale->scale_factor/2)-round($this->text_scale_abscenteroff/2);
|
---|
2147 | }
|
---|
2148 | else {
|
---|
2149 | $this->xscale->off += ceil($this->xscale->scale_factor*$this->text_scale_off*$this->xscale->ticks->minor_step);
|
---|
2150 | }
|
---|
2151 | }
|
---|
2152 |
|
---|
2153 | if( $this->iDoClipping ) {
|
---|
2154 | $oldimage = $this->img->CloneCanvasH();
|
---|
2155 | }
|
---|
2156 |
|
---|
2157 | if( ! $this->y2orderback ) {
|
---|
2158 | // Stroke all plots for Y1 axis
|
---|
2159 | for($i=0; $i < count($this->plots); ++$i) {
|
---|
2160 | $this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale);
|
---|
2161 | $this->plots[$i]->StrokeMargin($this->img);
|
---|
2162 | }
|
---|
2163 | }
|
---|
2164 |
|
---|
2165 | // Stroke all plots for Y2 axis
|
---|
2166 | if( $this->y2scale != null ) {
|
---|
2167 | for($i=0; $i< count($this->y2plots); ++$i ) {
|
---|
2168 | $this->y2plots[$i]->Stroke($this->img,$this->xscale,$this->y2scale);
|
---|
2169 | }
|
---|
2170 | }
|
---|
2171 |
|
---|
2172 | if( $this->y2orderback ) {
|
---|
2173 | // Stroke all plots for Y1 axis
|
---|
2174 | for($i=0; $i < count($this->plots); ++$i) {
|
---|
2175 | $this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale);
|
---|
2176 | $this->plots[$i]->StrokeMargin($this->img);
|
---|
2177 | }
|
---|
2178 | }
|
---|
2179 |
|
---|
2180 | $n = count($this->ynaxis);
|
---|
2181 | for( $i=0; $i < $n; ++$i ) {
|
---|
2182 | $m = count($this->ynplots[$i]);
|
---|
2183 | for( $j=0; $j < $m; ++$j ) {
|
---|
2184 | $this->ynplots[$i][$j]->Stroke($this->img,$this->xscale,$this->ynscale[$i]);
|
---|
2185 | $this->ynplots[$i][$j]->StrokeMargin($this->img);
|
---|
2186 | }
|
---|
2187 | }
|
---|
2188 |
|
---|
2189 | if( $this->iIconDepth == DEPTH_FRONT) {
|
---|
2190 | $this->StrokeIcons();
|
---|
2191 | }
|
---|
2192 |
|
---|
2193 | if( $this->iDoClipping ) {
|
---|
2194 | // Clipping only supports graphs at 0 and 90 degrees
|
---|
2195 | if( $this->img->a == 0 ) {
|
---|
2196 | $this->img->CopyCanvasH($oldimage,$this->img->img,
|
---|
2197 | $this->img->left_margin,$this->img->top_margin,
|
---|
2198 | $this->img->left_margin,$this->img->top_margin,
|
---|
2199 | $this->img->plotwidth+1,$this->img->plotheight);
|
---|
2200 | }
|
---|
2201 | elseif( $this->img->a == 90 ) {
|
---|
2202 | $adj = ($this->img->height - $this->img->width)/2;
|
---|
2203 | $this->img->CopyCanvasH($oldimage,$this->img->img,
|
---|
2204 | $this->img->bottom_margin-$adj,$this->img->left_margin+$adj,
|
---|
2205 | $this->img->bottom_margin-$adj,$this->img->left_margin+$adj,
|
---|
2206 | $this->img->plotheight+1,$this->img->plotwidth);
|
---|
2207 | }
|
---|
2208 | else {
|
---|
2209 | JpGraphError::RaiseL(25035,$this->img->a);//('You have enabled clipping. Cliping is only supported for graphs at 0 or 90 degrees rotation. Please adjust you current angle (='.$this->img->a.' degrees) or disable clipping.');
|
---|
2210 | }
|
---|
2211 | $this->img->Destroy();
|
---|
2212 | $this->img->SetCanvasH($oldimage);
|
---|
2213 | }
|
---|
2214 |
|
---|
2215 | $this->xscale->off=$oldoff;
|
---|
2216 |
|
---|
2217 | if( $this->grid_depth == DEPTH_FRONT && !$_csim ) {
|
---|
2218 | $this->ygrid->Stroke();
|
---|
2219 | $this->xgrid->Stroke();
|
---|
2220 | }
|
---|
2221 |
|
---|
2222 | // Stroke colored bands
|
---|
2223 | $this->StrokeBands(DEPTH_FRONT,$_csim);
|
---|
2224 |
|
---|
2225 | // Finally draw the axis again since some plots may have nagged
|
---|
2226 | // the axis in the edges.
|
---|
2227 | if( !$_csim ) {
|
---|
2228 | $this->StrokeAxis();
|
---|
2229 | }
|
---|
2230 |
|
---|
2231 | if( $this->y2scale != null && !$_csim ) {
|
---|
2232 | $this->y2axis->Stroke($this->xscale,false);
|
---|
2233 | }
|
---|
2234 |
|
---|
2235 | if( !$_csim ) {
|
---|
2236 | $this->StrokePlotBox();
|
---|
2237 | }
|
---|
2238 |
|
---|
2239 | // The titles and legends never gets rotated so make sure
|
---|
2240 | // that the angle is 0 before stroking them
|
---|
2241 | $aa = $this->img->SetAngle(0);
|
---|
2242 | $this->StrokeTitles();
|
---|
2243 | $this->footer->Stroke($this->img);
|
---|
2244 | $this->legend->Stroke($this->img);
|
---|
2245 | $this->img->SetAngle($aa);
|
---|
2246 | $this->StrokeTexts();
|
---|
2247 | $this->StrokeTables();
|
---|
2248 |
|
---|
2249 | if( !$_csim ) {
|
---|
2250 |
|
---|
2251 | $this->img->SetAngle($aa);
|
---|
2252 |
|
---|
2253 | // Draw an outline around the image map
|
---|
2254 | if(_JPG_DEBUG) {
|
---|
2255 | $this->DisplayClientSideaImageMapAreas();
|
---|
2256 | }
|
---|
2257 |
|
---|
2258 | // Should we do any final image transformation
|
---|
2259 | if( $this->iImgTrans ) {
|
---|
2260 | if( !class_exists('ImgTrans',false) ) {
|
---|
2261 | require_once('jpgraph_imgtrans.php');
|
---|
2262 | //JpGraphError::Raise('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.');
|
---|
2263 | }
|
---|
2264 |
|
---|
2265 | $tform = new ImgTrans($this->img->img);
|
---|
2266 | $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist,
|
---|
2267 | $this->iImgTransDirection,$this->iImgTransHighQ,
|
---|
2268 | $this->iImgTransMinSize,$this->iImgTransFillColor,
|
---|
2269 | $this->iImgTransBorder);
|
---|
2270 | }
|
---|
2271 |
|
---|
2272 | // If the filename is given as the special "__handle"
|
---|
2273 | // then the image handler is returned and the image is NOT
|
---|
2274 | // streamed back
|
---|
2275 | if( $aStrokeFileName == _IMG_HANDLER ) {
|
---|
2276 | return $this->img->img;
|
---|
2277 | }
|
---|
2278 | else {
|
---|
2279 | // Finally stream the generated picture
|
---|
2280 | $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName);
|
---|
2281 | }
|
---|
2282 | }
|
---|
2283 | }
|
---|
2284 |
|
---|
2285 | function SetAxisLabelBackground($aType,$aXFColor='lightgray',$aXColor='black',$aYFColor='lightgray',$aYColor='black') {
|
---|
2286 | $this->iAxisLblBgType = $aType;
|
---|
2287 | $this->iXAxisLblBgFillColor = $aXFColor;
|
---|
2288 | $this->iXAxisLblBgColor = $aXColor;
|
---|
2289 | $this->iYAxisLblBgFillColor = $aYFColor;
|
---|
2290 | $this->iYAxisLblBgColor = $aYColor;
|
---|
2291 | }
|
---|
2292 |
|
---|
2293 | function StrokeAxisLabelBackground() {
|
---|
2294 | // Types
|
---|
2295 | // 0 = No background
|
---|
2296 | // 1 = Only X-labels, length of axis
|
---|
2297 | // 2 = Only Y-labels, length of axis
|
---|
2298 | // 3 = As 1 but extends to width of graph
|
---|
2299 | // 4 = As 2 but extends to height of graph
|
---|
2300 | // 5 = Combination of 3 & 4
|
---|
2301 | // 6 = Combination of 1 & 2
|
---|
2302 |
|
---|
2303 | $t = $this->iAxisLblBgType ;
|
---|
2304 | if( $t < 1 ) return;
|
---|
2305 |
|
---|
2306 | // Stroke optional X-axis label background color
|
---|
2307 | if( $t == 1 || $t == 3 || $t == 5 || $t == 6 ) {
|
---|
2308 | $this->img->PushColor($this->iXAxisLblBgFillColor);
|
---|
2309 | if( $t == 1 || $t == 6 ) {
|
---|
2310 | $xl = $this->img->left_margin;
|
---|
2311 | $yu = $this->img->height - $this->img->bottom_margin + 1;
|
---|
2312 | $xr = $this->img->width - $this->img->right_margin ;
|
---|
2313 | $yl = $this->img->height-1-$this->frame_weight;
|
---|
2314 | }
|
---|
2315 | else { // t==3 || t==5
|
---|
2316 | $xl = $this->frame_weight;
|
---|
2317 | $yu = $this->img->height - $this->img->bottom_margin + 1;
|
---|
2318 | $xr = $this->img->width - 1 - $this->frame_weight;
|
---|
2319 | $yl = $this->img->height-1-$this->frame_weight;
|
---|
2320 | }
|
---|
2321 |
|
---|
2322 | $this->img->FilledRectangle($xl,$yu,$xr,$yl);
|
---|
2323 | $this->img->PopColor();
|
---|
2324 |
|
---|
2325 | // Check if we should add the vertical lines at left and right edge
|
---|
2326 | if( $this->iXAxisLblBgColor !== '' ) {
|
---|
2327 | // Hardcode to one pixel wide
|
---|
2328 | $this->img->SetLineWeight(1);
|
---|
2329 | $this->img->PushColor($this->iXAxisLblBgColor);
|
---|
2330 | if( $t == 1 || $t == 6 ) {
|
---|
2331 | $this->img->Line($xl,$yu,$xl,$yl);
|
---|
2332 | $this->img->Line($xr,$yu,$xr,$yl);
|
---|
2333 | }
|
---|
2334 | else {
|
---|
2335 | $xl = $this->img->width - $this->img->right_margin ;
|
---|
2336 | $this->img->Line($xl,$yu-1,$xr,$yu-1);
|
---|
2337 | }
|
---|
2338 | $this->img->PopColor();
|
---|
2339 | }
|
---|
2340 | }
|
---|
2341 |
|
---|
2342 | if( $t == 2 || $t == 4 || $t == 5 || $t == 6 ) {
|
---|
2343 | $this->img->PushColor($this->iYAxisLblBgFillColor);
|
---|
2344 | if( $t == 2 || $t == 6 ) {
|
---|
2345 | $xl = $this->frame_weight;
|
---|
2346 | $yu = $this->frame_weight+$this->img->top_margin;
|
---|
2347 | $xr = $this->img->left_margin - 1;
|
---|
2348 | $yl = $this->img->height - $this->img->bottom_margin + 1;
|
---|
2349 | }
|
---|
2350 | else {
|
---|
2351 | $xl = $this->frame_weight;
|
---|
2352 | $yu = $this->frame_weight;
|
---|
2353 | $xr = $this->img->left_margin - 1;
|
---|
2354 | $yl = $this->img->height-1-$this->frame_weight;
|
---|
2355 | }
|
---|
2356 |
|
---|
2357 | $this->img->FilledRectangle($xl,$yu,$xr,$yl);
|
---|
2358 | $this->img->PopColor();
|
---|
2359 |
|
---|
2360 | // Check if we should add the vertical lines at left and right edge
|
---|
2361 | if( $this->iXAxisLblBgColor !== '' ) {
|
---|
2362 | $this->img->PushColor($this->iXAxisLblBgColor);
|
---|
2363 | if( $t == 2 || $t == 6 ) {
|
---|
2364 | $this->img->Line($xl,$yu-1,$xr,$yu-1);
|
---|
2365 | $this->img->Line($xl,$yl-1,$xr,$yl-1);
|
---|
2366 | }
|
---|
2367 | else {
|
---|
2368 | $this->img->Line($xr+1,$yu,$xr+1,$this->img->top_margin);
|
---|
2369 | }
|
---|
2370 | $this->img->PopColor();
|
---|
2371 | }
|
---|
2372 |
|
---|
2373 | }
|
---|
2374 | }
|
---|
2375 |
|
---|
2376 | function StrokeAxis($aStrokeLabels=true) {
|
---|
2377 |
|
---|
2378 | if( $aStrokeLabels ) {
|
---|
2379 | $this->StrokeAxisLabelBackground();
|
---|
2380 | }
|
---|
2381 |
|
---|
2382 | // Stroke axis
|
---|
2383 | if( $this->iAxisStyle != AXSTYLE_SIMPLE ) {
|
---|
2384 | switch( $this->iAxisStyle ) {
|
---|
2385 | case AXSTYLE_BOXIN :
|
---|
2386 | $toppos = SIDE_DOWN;
|
---|
2387 | $bottompos = SIDE_UP;
|
---|
2388 | $leftpos = SIDE_RIGHT;
|
---|
2389 | $rightpos = SIDE_LEFT;
|
---|
2390 | break;
|
---|
2391 | case AXSTYLE_BOXOUT :
|
---|
2392 | $toppos = SIDE_UP;
|
---|
2393 | $bottompos = SIDE_DOWN;
|
---|
2394 | $leftpos = SIDE_LEFT;
|
---|
2395 | $rightpos = SIDE_RIGHT;
|
---|
2396 | break;
|
---|
2397 | case AXSTYLE_YBOXIN:
|
---|
2398 | $toppos = FALSE;
|
---|
2399 | $bottompos = SIDE_UP;
|
---|
2400 | $leftpos = SIDE_RIGHT;
|
---|
2401 | $rightpos = SIDE_LEFT;
|
---|
2402 | break;
|
---|
2403 | case AXSTYLE_YBOXOUT:
|
---|
2404 | $toppos = FALSE;
|
---|
2405 | $bottompos = SIDE_DOWN;
|
---|
2406 | $leftpos = SIDE_LEFT;
|
---|
2407 | $rightpos = SIDE_RIGHT;
|
---|
2408 | break;
|
---|
2409 | default:
|
---|
2410 | JpGRaphError::RaiseL(25036,$this->iAxisStyle); //('Unknown AxisStyle() : '.$this->iAxisStyle);
|
---|
2411 | break;
|
---|
2412 | }
|
---|
2413 |
|
---|
2414 | // By default we hide the first label so it doesn't cross the
|
---|
2415 | // Y-axis in case the positon hasn't been set by the user.
|
---|
2416 | // However, if we use a box we always want the first value
|
---|
2417 | // displayed so we make sure it will be displayed.
|
---|
2418 | $this->xscale->ticks->SupressFirst(false);
|
---|
2419 |
|
---|
2420 | // Now draw the bottom X-axis
|
---|
2421 | $this->xaxis->SetPos('min');
|
---|
2422 | $this->xaxis->SetLabelSide(SIDE_DOWN);
|
---|
2423 | $this->xaxis->scale->ticks->SetSide($bottompos);
|
---|
2424 | $this->xaxis->Stroke($this->yscale,$aStrokeLabels);
|
---|
2425 |
|
---|
2426 | if( $toppos !== FALSE ) {
|
---|
2427 | // We also want a top X-axis
|
---|
2428 | $this->xaxis = $this->xaxis;
|
---|
2429 | $this->xaxis->SetPos('max');
|
---|
2430 | $this->xaxis->SetLabelSide(SIDE_UP);
|
---|
2431 | // No title for the top X-axis
|
---|
2432 | if( $aStrokeLabels ) {
|
---|
2433 | $this->xaxis->title->Set('');
|
---|
2434 | }
|
---|
2435 | $this->xaxis->scale->ticks->SetSide($toppos);
|
---|
2436 | $this->xaxis->Stroke($this->yscale,$aStrokeLabels);
|
---|
2437 | }
|
---|
2438 |
|
---|
2439 | // Stroke the left Y-axis
|
---|
2440 | $this->yaxis->SetPos('min');
|
---|
2441 | $this->yaxis->SetLabelSide(SIDE_LEFT);
|
---|
2442 | $this->yaxis->scale->ticks->SetSide($leftpos);
|
---|
2443 | $this->yaxis->Stroke($this->xscale,$aStrokeLabels);
|
---|
2444 |
|
---|
2445 | // Stroke the right Y-axis
|
---|
2446 | $this->yaxis->SetPos('max');
|
---|
2447 | // No title for the right side
|
---|
2448 | if( $aStrokeLabels ) {
|
---|
2449 | $this->yaxis->title->Set('');
|
---|
2450 | }
|
---|
2451 | $this->yaxis->SetLabelSide(SIDE_RIGHT);
|
---|
2452 | $this->yaxis->scale->ticks->SetSide($rightpos);
|
---|
2453 | $this->yaxis->Stroke($this->xscale,$aStrokeLabels);
|
---|
2454 | }
|
---|
2455 | else {
|
---|
2456 | $this->xaxis->Stroke($this->yscale,$aStrokeLabels);
|
---|
2457 | $this->yaxis->Stroke($this->xscale,$aStrokeLabels);
|
---|
2458 | }
|
---|
2459 | }
|
---|
2460 |
|
---|
2461 |
|
---|
2462 | // Private helper function for backgound image
|
---|
2463 | static function LoadBkgImage($aImgFormat='',$aFile='',$aImgStr='') {
|
---|
2464 | if( $aImgStr != '' ) {
|
---|
2465 | return Image::CreateFromString($aImgStr);
|
---|
2466 | }
|
---|
2467 |
|
---|
2468 | // Remove case sensitivity and setup appropriate function to create image
|
---|
2469 | // Get file extension. This should be the LAST '.' separated part of the filename
|
---|
2470 | $e = explode('.',$aFile);
|
---|
2471 | $ext = strtolower($e[count($e)-1]);
|
---|
2472 | if ($ext == "jpeg") {
|
---|
2473 | $ext = "jpg";
|
---|
2474 | }
|
---|
2475 |
|
---|
2476 | if( trim($ext) == '' ) {
|
---|
2477 | $ext = 'png'; // Assume PNG if no extension specified
|
---|
2478 | }
|
---|
2479 |
|
---|
2480 | if( $aImgFormat == '' ) {
|
---|
2481 | $imgtag = $ext;
|
---|
2482 | }
|
---|
2483 | else {
|
---|
2484 | $imgtag = $aImgFormat;
|
---|
2485 | }
|
---|
2486 |
|
---|
2487 | $supported = imagetypes();
|
---|
2488 | if( ( $ext == 'jpg' && !($supported & IMG_JPG) ) ||
|
---|
2489 | ( $ext == 'gif' && !($supported & IMG_GIF) ) ||
|
---|
2490 | ( $ext == 'png' && !($supported & IMG_PNG) ) ||
|
---|
2491 | ( $ext == 'bmp' && !($supported & IMG_WBMP) ) ||
|
---|
2492 | ( $ext == 'xpm' && !($supported & IMG_XPM) ) ) {
|
---|
2493 |
|
---|
2494 | JpGraphError::RaiseL(25037,$aFile);//('The image format of your background image ('.$aFile.') is not supported in your system configuration. ');
|
---|
2495 | }
|
---|
2496 |
|
---|
2497 |
|
---|
2498 | if( $imgtag == "jpg" || $imgtag == "jpeg") {
|
---|
2499 | $f = "imagecreatefromjpeg";
|
---|
2500 | $imgtag = "jpg";
|
---|
2501 | }
|
---|
2502 | else {
|
---|
2503 | $f = "imagecreatefrom".$imgtag;
|
---|
2504 | }
|
---|
2505 |
|
---|
2506 | // Compare specified image type and file extension
|
---|
2507 | if( $imgtag != $ext ) {
|
---|
2508 | //$t = "Background image seems to be of different type (has different file extension) than specified imagetype. Specified: '".$aImgFormat."'File: '".$aFile."'";
|
---|
2509 | JpGraphError::RaiseL(25038, $aImgFormat, $aFile);
|
---|
2510 | }
|
---|
2511 |
|
---|
2512 | $img = @$f($aFile);
|
---|
2513 | if( !$img ) {
|
---|
2514 | JpGraphError::RaiseL(25039,$aFile);//(" Can't read background image: '".$aFile."'");
|
---|
2515 | }
|
---|
2516 | return $img;
|
---|
2517 | }
|
---|
2518 |
|
---|
2519 | function StrokePlotGrad() {
|
---|
2520 | if( $this->plot_gradtype < 0 )
|
---|
2521 | return;
|
---|
2522 |
|
---|
2523 | $grad = new Gradient($this->img);
|
---|
2524 | $xl = $this->img->left_margin;
|
---|
2525 | $yt = $this->img->top_margin;
|
---|
2526 | $xr = $xl + $this->img->plotwidth+1 ;
|
---|
2527 | $yb = $yt + $this->img->plotheight ;
|
---|
2528 | $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->plot_gradfrom,$this->plot_gradto,$this->plot_gradtype);
|
---|
2529 |
|
---|
2530 | }
|
---|
2531 |
|
---|
2532 | function StrokeBackgroundGrad() {
|
---|
2533 | if( $this->bkg_gradtype < 0 )
|
---|
2534 | return;
|
---|
2535 |
|
---|
2536 | $grad = new Gradient($this->img);
|
---|
2537 | if( $this->bkg_gradstyle == BGRAD_PLOT ) {
|
---|
2538 | $xl = $this->img->left_margin;
|
---|
2539 | $yt = $this->img->top_margin;
|
---|
2540 | $xr = $xl + $this->img->plotwidth+1 ;
|
---|
2541 | $yb = $yt + $this->img->plotheight ;
|
---|
2542 | $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->bkg_gradfrom,$this->bkg_gradto,$this->bkg_gradtype);
|
---|
2543 | }
|
---|
2544 | else {
|
---|
2545 | $xl = 0;
|
---|
2546 | $yt = 0;
|
---|
2547 | $xr = $xl + $this->img->width - 1;
|
---|
2548 | $yb = $yt + $this->img->height - 1 ;
|
---|
2549 | if( $this->doshadow ) {
|
---|
2550 | $xr -= $this->shadow_width;
|
---|
2551 | $yb -= $this->shadow_width;
|
---|
2552 | }
|
---|
2553 | if( $this->doframe ) {
|
---|
2554 | $yt += $this->frame_weight;
|
---|
2555 | $yb -= $this->frame_weight;
|
---|
2556 | $xl += $this->frame_weight;
|
---|
2557 | $xr -= $this->frame_weight;
|
---|
2558 | }
|
---|
2559 | $aa = $this->img->SetAngle(0);
|
---|
2560 | $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->bkg_gradfrom,$this->bkg_gradto,$this->bkg_gradtype);
|
---|
2561 | $aa = $this->img->SetAngle($aa);
|
---|
2562 | }
|
---|
2563 | }
|
---|
2564 |
|
---|
2565 | function StrokeFrameBackground() {
|
---|
2566 | if( $this->background_image != '' && $this->background_cflag != '' ) {
|
---|
2567 | JpGraphError::RaiseL(25040);//('It is not possible to specify both a background image and a background country flag.');
|
---|
2568 | }
|
---|
2569 | if( $this->background_image != '' ) {
|
---|
2570 | $bkgimg = $this->LoadBkgImage($this->background_image_format,$this->background_image);
|
---|
2571 | }
|
---|
2572 | elseif( $this->background_cflag != '' ) {
|
---|
2573 | if( ! class_exists('FlagImages',false) ) {
|
---|
2574 | JpGraphError::RaiseL(25041);//('In order to use Country flags as backgrounds you must include the "jpgraph_flags.php" file.');
|
---|
2575 | }
|
---|
2576 | $fobj = new FlagImages(FLAGSIZE4);
|
---|
2577 | $dummy='';
|
---|
2578 | $bkgimg = $fobj->GetImgByName($this->background_cflag,$dummy);
|
---|
2579 | $this->background_image_mix = $this->background_cflag_mix;
|
---|
2580 | $this->background_image_type = $this->background_cflag_type;
|
---|
2581 | }
|
---|
2582 | else {
|
---|
2583 | return ;
|
---|
2584 | }
|
---|
2585 |
|
---|
2586 | $bw = ImageSX($bkgimg);
|
---|
2587 | $bh = ImageSY($bkgimg);
|
---|
2588 |
|
---|
2589 | // No matter what the angle is we always stroke the image and frame
|
---|
2590 | // assuming it is 0 degree
|
---|
2591 | $aa = $this->img->SetAngle(0);
|
---|
2592 |
|
---|
2593 | switch( $this->background_image_type ) {
|
---|
2594 | case BGIMG_FILLPLOT: // Resize to just fill the plotarea
|
---|
2595 | $this->FillMarginArea();
|
---|
2596 | $this->StrokeFrame();
|
---|
2597 | // Special case to hande 90 degree rotated graph corectly
|
---|
2598 | if( $aa == 90 ) {
|
---|
2599 | $this->img->SetAngle(90);
|
---|
2600 | $this->FillPlotArea();
|
---|
2601 | $aa = $this->img->SetAngle(0);
|
---|
2602 | $adj = ($this->img->height - $this->img->width)/2;
|
---|
2603 | $this->img->CopyMerge($bkgimg,
|
---|
2604 | $this->img->bottom_margin-$adj,$this->img->left_margin+$adj,
|
---|
2605 | 0,0,
|
---|
2606 | $this->img->plotheight+1,$this->img->plotwidth,
|
---|
2607 | $bw,$bh,$this->background_image_mix);
|
---|
2608 | }
|
---|
2609 | else {
|
---|
2610 | $this->FillPlotArea();
|
---|
2611 | $this->img->CopyMerge($bkgimg,
|
---|
2612 | $this->img->left_margin,$this->img->top_margin+1,
|
---|
2613 | 0,0,$this->img->plotwidth+1,$this->img->plotheight,
|
---|
2614 | $bw,$bh,$this->background_image_mix);
|
---|
2615 | }
|
---|
2616 | break;
|
---|
2617 | case BGIMG_FILLFRAME: // Fill the whole area from upper left corner, resize to just fit
|
---|
2618 | $hadj=0; $vadj=0;
|
---|
2619 | if( $this->doshadow ) {
|
---|
2620 | $hadj = $this->shadow_width;
|
---|
2621 | $vadj = $this->shadow_width;
|
---|
2622 | }
|
---|
2623 | $this->FillMarginArea();
|
---|
2624 | $this->FillPlotArea();
|
---|
2625 | $this->img->CopyMerge($bkgimg,0,0,0,0,$this->img->width-$hadj,$this->img->height-$vadj,
|
---|
2626 | $bw,$bh,$this->background_image_mix);
|
---|
2627 | $this->StrokeFrame();
|
---|
2628 | break;
|
---|
2629 | case BGIMG_COPY: // Just copy the image from left corner, no resizing
|
---|
2630 | $this->FillMarginArea();
|
---|
2631 | $this->FillPlotArea();
|
---|
2632 | $this->img->CopyMerge($bkgimg,0,0,0,0,$bw,$bh,
|
---|
2633 | $bw,$bh,$this->background_image_mix);
|
---|
2634 | $this->StrokeFrame();
|
---|
2635 | break;
|
---|
2636 | case BGIMG_CENTER: // Center original image in the plot area
|
---|
2637 | $this->FillMarginArea();
|
---|
2638 | $this->FillPlotArea();
|
---|
2639 | $centerx = round($this->img->plotwidth/2+$this->img->left_margin-$bw/2);
|
---|
2640 | $centery = round($this->img->plotheight/2+$this->img->top_margin-$bh/2);
|
---|
2641 | $this->img->CopyMerge($bkgimg,$centerx,$centery,0,0,$bw,$bh,
|
---|
2642 | $bw,$bh,$this->background_image_mix);
|
---|
2643 | $this->StrokeFrame();
|
---|
2644 | break;
|
---|
2645 | case BGIMG_FREE: // Just copy the image to the specified location
|
---|
2646 | $this->img->CopyMerge($bkgimg,
|
---|
2647 | $this->background_image_xpos,$this->background_image_ypos,
|
---|
2648 | 0,0,$bw,$bh,$bw,$bh,$this->background_image_mix);
|
---|
2649 | $this->StrokeFrame(); // New
|
---|
2650 | break;
|
---|
2651 | default:
|
---|
2652 | JpGraphError::RaiseL(25042);//(" Unknown background image layout");
|
---|
2653 | }
|
---|
2654 | $this->img->SetAngle($aa);
|
---|
2655 | }
|
---|
2656 |
|
---|
2657 | // Private
|
---|
2658 | // Draw a frame around the image
|
---|
2659 | function StrokeFrame() {
|
---|
2660 | if( !$this->doframe ) return;
|
---|
2661 |
|
---|
2662 | if( $this->background_image_type <= 1 && ($this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_PLOT)) ) {
|
---|
2663 | $c = $this->margin_color;
|
---|
2664 | }
|
---|
2665 | else {
|
---|
2666 | $c = false;
|
---|
2667 | }
|
---|
2668 |
|
---|
2669 | if( $this->doshadow ) {
|
---|
2670 | $this->img->SetColor($this->frame_color);
|
---|
2671 | $this->img->ShadowRectangle(0,0,$this->img->width,$this->img->height,
|
---|
2672 | $c,$this->shadow_width,$this->shadow_color);
|
---|
2673 | }
|
---|
2674 | elseif( $this->framebevel ) {
|
---|
2675 | if( $c ) {
|
---|
2676 | $this->img->SetColor($this->margin_color);
|
---|
2677 | $this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1);
|
---|
2678 | }
|
---|
2679 | $this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2,
|
---|
2680 | $this->framebeveldepth,
|
---|
2681 | $this->framebevelcolor1,$this->framebevelcolor2);
|
---|
2682 | if( $this->framebevelborder ) {
|
---|
2683 | $this->img->SetColor($this->framebevelbordercolor);
|
---|
2684 | $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1);
|
---|
2685 | }
|
---|
2686 | }
|
---|
2687 | else {
|
---|
2688 | $this->img->SetLineWeight($this->frame_weight);
|
---|
2689 | if( $c ) {
|
---|
2690 | $this->img->SetColor($this->margin_color);
|
---|
2691 | $this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1);
|
---|
2692 | }
|
---|
2693 | $this->img->SetColor($this->frame_color);
|
---|
2694 | $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1);
|
---|
2695 | }
|
---|
2696 | }
|
---|
2697 |
|
---|
2698 | function FillMarginArea() {
|
---|
2699 | $hadj=0; $vadj=0;
|
---|
2700 | if( $this->doshadow ) {
|
---|
2701 | $hadj = $this->shadow_width;
|
---|
2702 | $vadj = $this->shadow_width;
|
---|
2703 | }
|
---|
2704 |
|
---|
2705 | $this->img->SetColor($this->margin_color);
|
---|
2706 | $this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->height-1-$vadj);
|
---|
2707 |
|
---|
2708 | $this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->top_margin);
|
---|
2709 | $this->img->FilledRectangle(0,$this->img->top_margin,$this->img->left_margin,$this->img->height-1-$hadj);
|
---|
2710 | $this->img->FilledRectangle($this->img->left_margin+1,
|
---|
2711 | $this->img->height-$this->img->bottom_margin,
|
---|
2712 | $this->img->width-1-$hadj,
|
---|
2713 | $this->img->height-1-$hadj);
|
---|
2714 | $this->img->FilledRectangle($this->img->width-$this->img->right_margin,
|
---|
2715 | $this->img->top_margin+1,
|
---|
2716 | $this->img->width-1-$hadj,
|
---|
2717 | $this->img->height-$this->img->bottom_margin-1);
|
---|
2718 | }
|
---|
2719 |
|
---|
2720 | function FillPlotArea() {
|
---|
2721 | $this->img->PushColor($this->plotarea_color);
|
---|
2722 | $this->img->FilledRectangle($this->img->left_margin,
|
---|
2723 | $this->img->top_margin,
|
---|
2724 | $this->img->width-$this->img->right_margin,
|
---|
2725 | $this->img->height-$this->img->bottom_margin);
|
---|
2726 | $this->img->PopColor();
|
---|
2727 | }
|
---|
2728 |
|
---|
2729 | // Stroke the plot area with either a solid color or a background image
|
---|
2730 | function StrokePlotArea() {
|
---|
2731 | // Note: To be consistent we really should take a possible shadow
|
---|
2732 | // into account. However, that causes some problem for the LinearScale class
|
---|
2733 | // since in the current design it does not have any links to class Graph which
|
---|
2734 | // means it has no way of compensating for the adjusted plotarea in case of a
|
---|
2735 | // shadow. So, until I redesign LinearScale we can't compensate for this.
|
---|
2736 | // So just set the two adjustment parameters to zero for now.
|
---|
2737 | $boxadj = 0; //$this->doframe ? $this->frame_weight : 0 ;
|
---|
2738 | $adj = 0; //$this->doshadow ? $this->shadow_width : 0 ;
|
---|
2739 |
|
---|
2740 | if( $this->background_image != '' || $this->background_cflag != '' ) {
|
---|
2741 | $this->StrokeFrameBackground();
|
---|
2742 | }
|
---|
2743 | else {
|
---|
2744 | $aa = $this->img->SetAngle(0);
|
---|
2745 | $this->StrokeFrame();
|
---|
2746 | $aa = $this->img->SetAngle($aa);
|
---|
2747 | $this->StrokeBackgroundGrad();
|
---|
2748 | if( $this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_MARGIN) ) {
|
---|
2749 | $this->FillPlotArea();
|
---|
2750 | }
|
---|
2751 | $this->StrokePlotGrad();
|
---|
2752 | }
|
---|
2753 | }
|
---|
2754 |
|
---|
2755 | function StrokeIcons() {
|
---|
2756 | $n = count($this->iIcons);
|
---|
2757 | for( $i=0; $i < $n; ++$i ) {
|
---|
2758 | $this->iIcons[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale);
|
---|
2759 | }
|
---|
2760 | }
|
---|
2761 |
|
---|
2762 | function StrokePlotBox() {
|
---|
2763 | // Should we draw a box around the plot area?
|
---|
2764 | if( $this->boxed ) {
|
---|
2765 | $this->img->SetLineWeight(1);
|
---|
2766 | $this->img->SetLineStyle('solid');
|
---|
2767 | $this->img->SetColor($this->box_color);
|
---|
2768 | for($i=0; $i < $this->box_weight; ++$i ) {
|
---|
2769 | $this->img->Rectangle(
|
---|
2770 | $this->img->left_margin-$i,$this->img->top_margin-$i,
|
---|
2771 | $this->img->width-$this->img->right_margin+$i,
|
---|
2772 | $this->img->height-$this->img->bottom_margin+$i);
|
---|
2773 | }
|
---|
2774 | }
|
---|
2775 | }
|
---|
2776 |
|
---|
2777 | function SetTitleBackgroundFillStyle($aStyle,$aColor1='black',$aColor2='white') {
|
---|
2778 | $this->titlebkg_fillstyle = $aStyle;
|
---|
2779 | $this->titlebkg_scolor1 = $aColor1;
|
---|
2780 | $this->titlebkg_scolor2 = $aColor2;
|
---|
2781 | }
|
---|
2782 |
|
---|
2783 | function SetTitleBackground($aBackColor='gray', $aStyle=TITLEBKG_STYLE1, $aFrameStyle=TITLEBKG_FRAME_NONE, $aFrameColor='black', $aFrameWeight=1, $aBevelHeight=3, $aEnable=true) {
|
---|
2784 | $this->titlebackground = $aEnable;
|
---|
2785 | $this->titlebackground_color = $aBackColor;
|
---|
2786 | $this->titlebackground_style = $aStyle;
|
---|
2787 | $this->titlebackground_framecolor = $aFrameColor;
|
---|
2788 | $this->titlebackground_framestyle = $aFrameStyle;
|
---|
2789 | $this->titlebackground_frameweight = $aFrameWeight;
|
---|
2790 | $this->titlebackground_bevelheight = $aBevelHeight ;
|
---|
2791 | }
|
---|
2792 |
|
---|
2793 |
|
---|
2794 | function StrokeTitles() {
|
---|
2795 |
|
---|
2796 | $margin=3;
|
---|
2797 |
|
---|
2798 | if( $this->titlebackground ) {
|
---|
2799 | // Find out height
|
---|
2800 | $this->title->margin += 2 ;
|
---|
2801 | $h = $this->title->GetTextHeight($this->img)+$this->title->margin+$margin;
|
---|
2802 | if( $this->subtitle->t != '' && !$this->subtitle->hide ) {
|
---|
2803 | $h += $this->subtitle->GetTextHeight($this->img)+$margin+
|
---|
2804 | $this->subtitle->margin;
|
---|
2805 | $h += 2;
|
---|
2806 | }
|
---|
2807 | if( $this->subsubtitle->t != '' && !$this->subsubtitle->hide ) {
|
---|
2808 | $h += $this->subsubtitle->GetTextHeight($this->img)+$margin+
|
---|
2809 | $this->subsubtitle->margin;
|
---|
2810 | $h += 2;
|
---|
2811 | }
|
---|
2812 | $this->img->PushColor($this->titlebackground_color);
|
---|
2813 | if( $this->titlebackground_style === TITLEBKG_STYLE1 ) {
|
---|
2814 | // Inside the frame
|
---|
2815 | if( $this->framebevel ) {
|
---|
2816 | $x1 = $y1 = $this->framebeveldepth + 1 ;
|
---|
2817 | $x2 = $this->img->width - $this->framebeveldepth - 2 ;
|
---|
2818 | $this->title->margin += $this->framebeveldepth + 1 ;
|
---|
2819 | $h += $y1 ;
|
---|
2820 | $h += 2;
|
---|
2821 | }
|
---|
2822 | else {
|
---|
2823 | $x1 = $y1 = $this->frame_weight;
|
---|
2824 | $x2 = $this->img->width - $this->frame_weight-1;
|
---|
2825 | }
|
---|
2826 | }
|
---|
2827 | elseif( $this->titlebackground_style === TITLEBKG_STYLE2 ) {
|
---|
2828 | // Cover the frame as well
|
---|
2829 | $x1 = $y1 = 0;
|
---|
2830 | $x2 = $this->img->width - 1 ;
|
---|
2831 | }
|
---|
2832 | elseif( $this->titlebackground_style === TITLEBKG_STYLE3 ) {
|
---|
2833 | // Cover the frame as well (the difference is that
|
---|
2834 | // for style==3 a bevel frame border is on top
|
---|
2835 | // of the title background)
|
---|
2836 | $x1 = $y1 = 0;
|
---|
2837 | $x2 = $this->img->width - 1 ;
|
---|
2838 | $h += $this->framebeveldepth ;
|
---|
2839 | $this->title->margin += $this->framebeveldepth ;
|
---|
2840 | }
|
---|
2841 | else {
|
---|
2842 | JpGraphError::RaiseL(25043);//('Unknown title background style.');
|
---|
2843 | }
|
---|
2844 |
|
---|
2845 | if( $this->titlebackground_framestyle === 3 ) {
|
---|
2846 | $h += $this->titlebackground_bevelheight*2 + 1 ;
|
---|
2847 | $this->title->margin += $this->titlebackground_bevelheight ;
|
---|
2848 | }
|
---|
2849 |
|
---|
2850 | if( $this->doshadow ) {
|
---|
2851 | $x2 -= $this->shadow_width ;
|
---|
2852 | }
|
---|
2853 |
|
---|
2854 | $indent=0;
|
---|
2855 | if( $this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL ) {
|
---|
2856 | $indent = $this->titlebackground_bevelheight;
|
---|
2857 | }
|
---|
2858 |
|
---|
2859 | if( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_HSTRIPED ) {
|
---|
2860 | $this->img->FilledRectangle2($x1+$indent,$y1+$indent,$x2-$indent,$h-$indent,
|
---|
2861 | $this->titlebkg_scolor1,
|
---|
2862 | $this->titlebkg_scolor2);
|
---|
2863 | }
|
---|
2864 | elseif( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_VSTRIPED ) {
|
---|
2865 | $this->img->FilledRectangle2($x1+$indent,$y1+$indent,$x2-$indent,$h-$indent,
|
---|
2866 | $this->titlebkg_scolor1,
|
---|
2867 | $this->titlebkg_scolor2,2);
|
---|
2868 | }
|
---|
2869 | else {
|
---|
2870 | // Solid fill
|
---|
2871 | $this->img->FilledRectangle($x1,$y1,$x2,$h);
|
---|
2872 | }
|
---|
2873 | $this->img->PopColor();
|
---|
2874 |
|
---|
2875 | $this->img->PushColor($this->titlebackground_framecolor);
|
---|
2876 | $this->img->SetLineWeight($this->titlebackground_frameweight);
|
---|
2877 | if( $this->titlebackground_framestyle == TITLEBKG_FRAME_FULL ) {
|
---|
2878 | // Frame background
|
---|
2879 | $this->img->Rectangle($x1,$y1,$x2,$h);
|
---|
2880 | }
|
---|
2881 | elseif( $this->titlebackground_framestyle == TITLEBKG_FRAME_BOTTOM ) {
|
---|
2882 | // Bottom line only
|
---|
2883 | $this->img->Line($x1,$h,$x2,$h);
|
---|
2884 | }
|
---|
2885 | elseif( $this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL ) {
|
---|
2886 | $this->img->Bevel($x1,$y1,$x2,$h,$this->titlebackground_bevelheight);
|
---|
2887 | }
|
---|
2888 | $this->img->PopColor();
|
---|
2889 |
|
---|
2890 | // This is clumsy. But we neeed to stroke the whole graph frame if it is
|
---|
2891 | // set to bevel to get the bevel shading on top of the text background
|
---|
2892 | if( $this->framebevel && $this->doframe && $this->titlebackground_style === 3 ) {
|
---|
2893 | $this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2,
|
---|
2894 | $this->framebeveldepth,
|
---|
2895 | $this->framebevelcolor1,$this->framebevelcolor2);
|
---|
2896 | if( $this->framebevelborder ) {
|
---|
2897 | $this->img->SetColor($this->framebevelbordercolor);
|
---|
2898 | $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1);
|
---|
2899 | }
|
---|
2900 | }
|
---|
2901 | }
|
---|
2902 |
|
---|
2903 | // Stroke title
|
---|
2904 | $y = $this->title->margin;
|
---|
2905 | if( $this->title->halign == 'center' ) {
|
---|
2906 | $this->title->Center(0,$this->img->width,$y);
|
---|
2907 | }
|
---|
2908 | elseif( $this->title->halign == 'left' ) {
|
---|
2909 | $this->title->SetPos($this->title->margin+2,$y);
|
---|
2910 | }
|
---|
2911 | elseif( $this->title->halign == 'right' ) {
|
---|
2912 | $indent = 0;
|
---|
2913 | if( $this->doshadow ) {
|
---|
2914 | $indent = $this->shadow_width+2;
|
---|
2915 | }
|
---|
2916 | $this->title->SetPos($this->img->width-$this->title->margin-$indent,$y,'right');
|
---|
2917 | }
|
---|
2918 | $this->title->Stroke($this->img);
|
---|
2919 |
|
---|
2920 | // ... and subtitle
|
---|
2921 | $y += $this->title->GetTextHeight($this->img) + $margin + $this->subtitle->margin;
|
---|
2922 | if( $this->subtitle->halign == 'center' ) {
|
---|
2923 | $this->subtitle->Center(0,$this->img->width,$y);
|
---|
2924 | }
|
---|
2925 | elseif( $this->subtitle->halign == 'left' ) {
|
---|
2926 | $this->subtitle->SetPos($this->subtitle->margin+2,$y);
|
---|
2927 | }
|
---|
2928 | elseif( $this->subtitle->halign == 'right' ) {
|
---|
2929 | $indent = 0;
|
---|
2930 | if( $this->doshadow )
|
---|
2931 | $indent = $this->shadow_width+2;
|
---|
2932 | $this->subtitle->SetPos($this->img->width-$this->subtitle->margin-$indent,$y,'right');
|
---|
2933 | }
|
---|
2934 | $this->subtitle->Stroke($this->img);
|
---|
2935 |
|
---|
2936 | // ... and subsubtitle
|
---|
2937 | $y += $this->subtitle->GetTextHeight($this->img) + $margin + $this->subsubtitle->margin;
|
---|
2938 | if( $this->subsubtitle->halign == 'center' ) {
|
---|
2939 | $this->subsubtitle->Center(0,$this->img->width,$y);
|
---|
2940 | }
|
---|
2941 | elseif( $this->subsubtitle->halign == 'left' ) {
|
---|
2942 | $this->subsubtitle->SetPos($this->subsubtitle->margin+2,$y);
|
---|
2943 | }
|
---|
2944 | elseif( $this->subsubtitle->halign == 'right' ) {
|
---|
2945 | $indent = 0;
|
---|
2946 | if( $this->doshadow )
|
---|
2947 | $indent = $this->shadow_width+2;
|
---|
2948 | $this->subsubtitle->SetPos($this->img->width-$this->subsubtitle->margin-$indent,$y,'right');
|
---|
2949 | }
|
---|
2950 | $this->subsubtitle->Stroke($this->img);
|
---|
2951 |
|
---|
2952 | // ... and fancy title
|
---|
2953 | $this->tabtitle->Stroke($this->img);
|
---|
2954 |
|
---|
2955 | }
|
---|
2956 |
|
---|
2957 | function StrokeTexts() {
|
---|
2958 | // Stroke any user added text objects
|
---|
2959 | if( $this->texts != null ) {
|
---|
2960 | for($i=0; $i < count($this->texts); ++$i) {
|
---|
2961 | $this->texts[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale);
|
---|
2962 | }
|
---|
2963 | }
|
---|
2964 |
|
---|
2965 | if( $this->y2texts != null && $this->y2scale != null ) {
|
---|
2966 | for($i=0; $i < count($this->y2texts); ++$i) {
|
---|
2967 | $this->y2texts[$i]->StrokeWithScale($this->img,$this->xscale,$this->y2scale);
|
---|
2968 | }
|
---|
2969 | }
|
---|
2970 |
|
---|
2971 | }
|
---|
2972 |
|
---|
2973 | function StrokeTables() {
|
---|
2974 | if( $this->iTables != null ) {
|
---|
2975 | $n = count($this->iTables);
|
---|
2976 | for( $i=0; $i < $n; ++$i ) {
|
---|
2977 | $this->iTables[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale);
|
---|
2978 | }
|
---|
2979 | }
|
---|
2980 | }
|
---|
2981 |
|
---|
2982 | function DisplayClientSideaImageMapAreas() {
|
---|
2983 | // Debug stuff - display the outline of the image map areas
|
---|
2984 | $csim='';
|
---|
2985 | foreach ($this->plots as $p) {
|
---|
2986 | $csim.= $p->GetCSIMareas();
|
---|
2987 | }
|
---|
2988 | $csim .= $this->legend->GetCSIMareas();
|
---|
2989 | if (preg_match_all("/area shape=\"(\w+)\" coords=\"([0-9\, ]+)\"/", $csim, $coords)) {
|
---|
2990 | $this->img->SetColor($this->csimcolor);
|
---|
2991 | $n = count($coords[0]);
|
---|
2992 | for ($i=0; $i < $n; $i++) {
|
---|
2993 | if ( $coords[1][$i] == 'poly' ) {
|
---|
2994 | preg_match_all('/\s*([0-9]+)\s*,\s*([0-9]+)\s*,*/',$coords[2][$i],$pts);
|
---|
2995 | $this->img->SetStartPoint($pts[1][count($pts[0])-1],$pts[2][count($pts[0])-1]);
|
---|
2996 | $m = count($pts[0]);
|
---|
2997 | for ($j=0; $j < $m; $j++) {
|
---|
2998 | $this->img->LineTo($pts[1][$j],$pts[2][$j]);
|
---|
2999 | }
|
---|
3000 | } elseif ( $coords[1][$i] == 'rect' ) {
|
---|
3001 | $pts = preg_split('/,/', $coords[2][$i]);
|
---|
3002 | $this->img->SetStartPoint($pts[0],$pts[1]);
|
---|
3003 | $this->img->LineTo($pts[2],$pts[1]);
|
---|
3004 | $this->img->LineTo($pts[2],$pts[3]);
|
---|
3005 | $this->img->LineTo($pts[0],$pts[3]);
|
---|
3006 | $this->img->LineTo($pts[0],$pts[1]);
|
---|
3007 | }
|
---|
3008 | }
|
---|
3009 | }
|
---|
3010 | }
|
---|
3011 |
|
---|
3012 | // Text scale offset in world coordinates
|
---|
3013 | function SetTextScaleOff($aOff) {
|
---|
3014 | $this->text_scale_off = $aOff;
|
---|
3015 | $this->xscale->text_scale_off = $aOff;
|
---|
3016 | }
|
---|
3017 |
|
---|
3018 | // Text width of bar to be centered in absolute pixels
|
---|
3019 | function SetTextScaleAbsCenterOff($aOff) {
|
---|
3020 | $this->text_scale_abscenteroff = $aOff;
|
---|
3021 | }
|
---|
3022 |
|
---|
3023 | // Get Y min and max values for added lines
|
---|
3024 | function GetLinesYMinMax( $aLines ) {
|
---|
3025 | $n = is_array($aLines) ? count($aLines) : 0;
|
---|
3026 | if( $n == 0 ) return false;
|
---|
3027 | $min = $aLines[0]->scaleposition ;
|
---|
3028 | $max = $min ;
|
---|
3029 | $flg = false;
|
---|
3030 | for( $i=0; $i < $n; ++$i ) {
|
---|
3031 | if( $aLines[$i]->direction == HORIZONTAL ) {
|
---|
3032 | $flg = true ;
|
---|
3033 | $v = $aLines[$i]->scaleposition ;
|
---|
3034 | if( $min > $v ) $min = $v ;
|
---|
3035 | if( $max < $v ) $max = $v ;
|
---|
3036 | }
|
---|
3037 | }
|
---|
3038 | return $flg ? array($min,$max) : false ;
|
---|
3039 | }
|
---|
3040 |
|
---|
3041 | // Get X min and max values for added lines
|
---|
3042 | function GetLinesXMinMax( $aLines ) {
|
---|
3043 | $n = is_array($aLines) ? count($aLines) : 0;
|
---|
3044 | if( $n == 0 ) return false ;
|
---|
3045 | $min = $aLines[0]->scaleposition ;
|
---|
3046 | $max = $min ;
|
---|
3047 | $flg = false;
|
---|
3048 | for( $i=0; $i < $n; ++$i ) {
|
---|
3049 | if( $aLines[$i]->direction == VERTICAL ) {
|
---|
3050 | $flg = true ;
|
---|
3051 | $v = $aLines[$i]->scaleposition ;
|
---|
3052 | if( $min > $v ) $min = $v ;
|
---|
3053 | if( $max < $v ) $max = $v ;
|
---|
3054 | }
|
---|
3055 | }
|
---|
3056 | return $flg ? array($min,$max) : false ;
|
---|
3057 | }
|
---|
3058 |
|
---|
3059 | // Get min and max values for all included plots
|
---|
3060 | function GetPlotsYMinMax($aPlots) {
|
---|
3061 | $n = count($aPlots);
|
---|
3062 | $i=0;
|
---|
3063 | do {
|
---|
3064 | list($xmax,$max) = $aPlots[$i]->Max();
|
---|
3065 | } while( ++$i < $n && !is_numeric($max) );
|
---|
3066 |
|
---|
3067 | $i=0;
|
---|
3068 | do {
|
---|
3069 | list($xmin,$min) = $aPlots[$i]->Min();
|
---|
3070 | } while( ++$i < $n && !is_numeric($min) );
|
---|
3071 |
|
---|
3072 | if( !is_numeric($min) || !is_numeric($max) ) {
|
---|
3073 | JpGraphError::RaiseL(25044);//('Cannot use autoscaling since it is impossible to determine a valid min/max value of the Y-axis (only null values).');
|
---|
3074 | }
|
---|
3075 |
|
---|
3076 | for($i=0; $i < $n; ++$i ) {
|
---|
3077 | list($xmax,$ymax)=$aPlots[$i]->Max();
|
---|
3078 | list($xmin,$ymin)=$aPlots[$i]->Min();
|
---|
3079 | if (is_numeric($ymax)) $max=max($max,$ymax);
|
---|
3080 | if (is_numeric($ymin)) $min=min($min,$ymin);
|
---|
3081 | }
|
---|
3082 | if( $min == '' ) $min = 0;
|
---|
3083 | if( $max == '' ) $max = 0;
|
---|
3084 | if( $min == 0 && $max == 0 ) {
|
---|
3085 | // Special case if all values are 0
|
---|
3086 | $min=0;$max=1;
|
---|
3087 | }
|
---|
3088 | return array($min,$max);
|
---|
3089 | }
|
---|
3090 |
|
---|
3091 | function hasLinePlotAndBarPlot() {
|
---|
3092 | $has_line = false;
|
---|
3093 | $has_bar = false;
|
---|
3094 |
|
---|
3095 | foreach ($this->plots as $plot) {
|
---|
3096 | if ($plot instanceof LinePlot) {
|
---|
3097 | $has_line = true;
|
---|
3098 | }
|
---|
3099 | if ($plot instanceof BarPlot) {
|
---|
3100 | $has_bar = true;
|
---|
3101 | }
|
---|
3102 | }
|
---|
3103 |
|
---|
3104 | if ($has_line && $has_bar) {
|
---|
3105 | return true;
|
---|
3106 | }
|
---|
3107 |
|
---|
3108 | return false;
|
---|
3109 | }
|
---|
3110 |
|
---|
3111 | function SetTheme($graph_theme) {
|
---|
3112 |
|
---|
3113 | if (!($this instanceof PieGraph)) {
|
---|
3114 | if (!$this->isAfterSetScale) {
|
---|
3115 | JpGraphError::RaiseL(25133);//('Use Graph::SetTheme() after Graph::SetScale().');
|
---|
3116 | }
|
---|
3117 | }
|
---|
3118 |
|
---|
3119 | if ($this->graph_theme) {
|
---|
3120 | $this->ClearTheme();
|
---|
3121 | }
|
---|
3122 | $this->graph_theme = $graph_theme;
|
---|
3123 | $this->graph_theme->ApplyGraph($this);
|
---|
3124 | }
|
---|
3125 |
|
---|
3126 | function ClearTheme() {
|
---|
3127 | $this->graph_theme = null;
|
---|
3128 |
|
---|
3129 | $this->isRunningClear = true;
|
---|
3130 |
|
---|
3131 | $this->__construct(
|
---|
3132 | $this->inputValues['aWidth'],
|
---|
3133 | $this->inputValues['aHeight'],
|
---|
3134 | $this->inputValues['aCachedName'],
|
---|
3135 | $this->inputValues['aTimeout'],
|
---|
3136 | $this->inputValues['aInline']
|
---|
3137 | );
|
---|
3138 |
|
---|
3139 | if (!($this instanceof PieGraph)) {
|
---|
3140 | if ($this->isAfterSetScale) {
|
---|
3141 | $this->SetScale(
|
---|
3142 | $this->inputValues['aAxisType'],
|
---|
3143 | $this->inputValues['aYMin'],
|
---|
3144 | $this->inputValues['aYMax'],
|
---|
3145 | $this->inputValues['aXMin'],
|
---|
3146 | $this->inputValues['aXMax']
|
---|
3147 | );
|
---|
3148 | }
|
---|
3149 | }
|
---|
3150 |
|
---|
3151 | $this->isRunningClear = false;
|
---|
3152 | }
|
---|
3153 |
|
---|
3154 | function SetSupersampling($do = false, $scale = 2) {
|
---|
3155 | if ($do) {
|
---|
3156 | define('SUPERSAMPLING_SCALE', $scale);
|
---|
3157 | // $this->img->scale = $scale;
|
---|
3158 | } else {
|
---|
3159 | define('SUPERSAMPLING_SCALE', 1);
|
---|
3160 | //$this->img->scale = 0;
|
---|
3161 | }
|
---|
3162 | }
|
---|
3163 |
|
---|
3164 | } // Class
|
---|
3165 |
|
---|
3166 | //===================================================
|
---|
3167 | // CLASS LineProperty
|
---|
3168 | // Description: Holds properties for a line
|
---|
3169 | //===================================================
|
---|
3170 | class LineProperty {
|
---|
3171 | public $iWeight=1, $iColor='black', $iStyle='solid', $iShow=false;
|
---|
3172 |
|
---|
3173 | function __construct($aWeight=1,$aColor='black',$aStyle='solid') {
|
---|
3174 | $this->iWeight = $aWeight;
|
---|
3175 | $this->iColor = $aColor;
|
---|
3176 | $this->iStyle = $aStyle;
|
---|
3177 | }
|
---|
3178 |
|
---|
3179 | function SetColor($aColor) {
|
---|
3180 | $this->iColor = $aColor;
|
---|
3181 | }
|
---|
3182 |
|
---|
3183 | function SetWeight($aWeight) {
|
---|
3184 | $this->iWeight = $aWeight;
|
---|
3185 | }
|
---|
3186 |
|
---|
3187 | function SetStyle($aStyle) {
|
---|
3188 | $this->iStyle = $aStyle;
|
---|
3189 | }
|
---|
3190 |
|
---|
3191 | function Show($aShow=true) {
|
---|
3192 | $this->iShow=$aShow;
|
---|
3193 | }
|
---|
3194 |
|
---|
3195 | function Stroke($aImg,$aX1,$aY1,$aX2,$aY2) {
|
---|
3196 | if( $this->iShow ) {
|
---|
3197 | $aImg->PushColor($this->iColor);
|
---|
3198 | $oldls = $aImg->line_style;
|
---|
3199 | $oldlw = $aImg->line_weight;
|
---|
3200 | $aImg->SetLineWeight($this->iWeight);
|
---|
3201 | $aImg->SetLineStyle($this->iStyle);
|
---|
3202 | $aImg->StyleLine($aX1,$aY1,$aX2,$aY2);
|
---|
3203 | $aImg->PopColor($this->iColor);
|
---|
3204 | $aImg->line_style = $oldls;
|
---|
3205 | $aImg->line_weight = $oldlw;
|
---|
3206 |
|
---|
3207 | }
|
---|
3208 | }
|
---|
3209 | }
|
---|
3210 |
|
---|
3211 | //===================================================
|
---|
3212 | // CLASS GraphTabTitle
|
---|
3213 | // Description: Draw "tab" titles on top of graphs
|
---|
3214 | //===================================================
|
---|
3215 | class GraphTabTitle extends Text{
|
---|
3216 | private $corner = 6 , $posx = 7, $posy = 4;
|
---|
3217 | private $fillcolor='lightyellow',$bordercolor='black';
|
---|
3218 | private $align = 'left', $width=TABTITLE_WIDTHFIT;
|
---|
3219 | function __construct() {
|
---|
3220 | $this->t = '';
|
---|
3221 | $this->font_style = FS_BOLD;
|
---|
3222 | $this->hide = true;
|
---|
3223 | $this->color = 'darkred';
|
---|
3224 | }
|
---|
3225 |
|
---|
3226 | function SetColor($aTxtColor,$aFillColor='lightyellow',$aBorderColor='black') {
|
---|
3227 | $this->color = $aTxtColor;
|
---|
3228 | $this->fillcolor = $aFillColor;
|
---|
3229 | $this->bordercolor = $aBorderColor;
|
---|
3230 | }
|
---|
3231 |
|
---|
3232 | function SetFillColor($aFillColor) {
|
---|
3233 | $this->fillcolor = $aFillColor;
|
---|
3234 | }
|
---|
3235 |
|
---|
3236 | function SetTabAlign($aAlign) {
|
---|
3237 | $this->align = $aAlign;
|
---|
3238 | }
|
---|
3239 |
|
---|
3240 | function SetWidth($aWidth) {
|
---|
3241 | $this->width = $aWidth ;
|
---|
3242 | }
|
---|
3243 |
|
---|
3244 | function Set($t) {
|
---|
3245 | $this->t = $t;
|
---|
3246 | $this->hide = false;
|
---|
3247 | }
|
---|
3248 |
|
---|
3249 | function SetCorner($aD) {
|
---|
3250 | $this->corner = $aD ;
|
---|
3251 | }
|
---|
3252 |
|
---|
3253 | function Stroke($aImg,$aDummy1=null,$aDummy2=null) {
|
---|
3254 | if( $this->hide )
|
---|
3255 | return;
|
---|
3256 | $this->boxed = false;
|
---|
3257 | $w = $this->GetWidth($aImg) + 2*$this->posx;
|
---|
3258 | $h = $this->GetTextHeight($aImg) + 2*$this->posy;
|
---|
3259 |
|
---|
3260 | $x = $aImg->left_margin;
|
---|
3261 | $y = $aImg->top_margin;
|
---|
3262 |
|
---|
3263 | if( $this->width === TABTITLE_WIDTHFIT ) {
|
---|
3264 | if( $this->align == 'left' ) {
|
---|
3265 | $p = array($x, $y,
|
---|
3266 | $x, $y-$h+$this->corner,
|
---|
3267 | $x + $this->corner,$y-$h,
|
---|
3268 | $x + $w - $this->corner, $y-$h,
|
---|
3269 | $x + $w, $y-$h+$this->corner,
|
---|
3270 | $x + $w, $y);
|
---|
3271 | }
|
---|
3272 | elseif( $this->align == 'center' ) {
|
---|
3273 | $x += round($aImg->plotwidth/2) - round($w/2);
|
---|
3274 | $p = array($x, $y,
|
---|
3275 | $x, $y-$h+$this->corner,
|
---|
3276 | $x + $this->corner, $y-$h,
|
---|
3277 | $x + $w - $this->corner, $y-$h,
|
---|
3278 | $x + $w, $y-$h+$this->corner,
|
---|
3279 | $x + $w, $y);
|
---|
3280 | }
|
---|
3281 | else {
|
---|
3282 | $x += $aImg->plotwidth -$w;
|
---|
3283 | $p = array($x, $y,
|
---|
3284 | $x, $y-$h+$this->corner,
|
---|
3285 | $x + $this->corner,$y-$h,
|
---|
3286 | $x + $w - $this->corner, $y-$h,
|
---|
3287 | $x + $w, $y-$h+$this->corner,
|
---|
3288 | $x + $w, $y);
|
---|
3289 | }
|
---|
3290 | }
|
---|
3291 | else {
|
---|
3292 | if( $this->width === TABTITLE_WIDTHFULL ) {
|
---|
3293 | $w = $aImg->plotwidth ;
|
---|
3294 | }
|
---|
3295 | else {
|
---|
3296 | $w = $this->width ;
|
---|
3297 | }
|
---|
3298 |
|
---|
3299 | // Make the tab fit the width of the plot area
|
---|
3300 | $p = array($x, $y,
|
---|
3301 | $x, $y-$h+$this->corner,
|
---|
3302 | $x + $this->corner,$y-$h,
|
---|
3303 | $x + $w - $this->corner, $y-$h,
|
---|
3304 | $x + $w, $y-$h+$this->corner,
|
---|
3305 | $x + $w, $y);
|
---|
3306 |
|
---|
3307 | }
|
---|
3308 | if( $this->halign == 'left' ) {
|
---|
3309 | $aImg->SetTextAlign('left','bottom');
|
---|
3310 | $x += $this->posx;
|
---|
3311 | $y -= $this->posy;
|
---|
3312 | }
|
---|
3313 | elseif( $this->halign == 'center' ) {
|
---|
3314 | $aImg->SetTextAlign('center','bottom');
|
---|
3315 | $x += $w/2;
|
---|
3316 | $y -= $this->posy;
|
---|
3317 | }
|
---|
3318 | else {
|
---|
3319 | $aImg->SetTextAlign('right','bottom');
|
---|
3320 | $x += $w - $this->posx;
|
---|
3321 | $y -= $this->posy;
|
---|
3322 | }
|
---|
3323 |
|
---|
3324 | $aImg->SetColor($this->fillcolor);
|
---|
3325 | $aImg->FilledPolygon($p);
|
---|
3326 |
|
---|
3327 | $aImg->SetColor($this->bordercolor);
|
---|
3328 | $aImg->Polygon($p,true);
|
---|
3329 |
|
---|
3330 | $aImg->SetColor($this->color);
|
---|
3331 | $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);
|
---|
3332 | $aImg->StrokeText($x,$y,$this->t,0,'center');
|
---|
3333 | }
|
---|
3334 |
|
---|
3335 | }
|
---|
3336 |
|
---|
3337 | //===================================================
|
---|
3338 | // CLASS SuperScriptText
|
---|
3339 | // Description: Format a superscript text
|
---|
3340 | //===================================================
|
---|
3341 | class SuperScriptText extends Text {
|
---|
3342 | private $iSuper='';
|
---|
3343 | private $sfont_family='',$sfont_style='',$sfont_size=8;
|
---|
3344 | private $iSuperMargin=2,$iVertOverlap=4,$iSuperScale=0.65;
|
---|
3345 | private $iSDir=0;
|
---|
3346 | private $iSimple=false;
|
---|
3347 |
|
---|
3348 | function __construct($aTxt='',$aSuper='',$aXAbsPos=0,$aYAbsPos=0) {
|
---|
3349 | parent::__construct($aTxt,$aXAbsPos,$aYAbsPos);
|
---|
3350 | $this->iSuper = $aSuper;
|
---|
3351 | }
|
---|
3352 |
|
---|
3353 | function FromReal($aVal,$aPrecision=2) {
|
---|
3354 | // Convert a floating point number to scientific notation
|
---|
3355 | $neg=1.0;
|
---|
3356 | if( $aVal < 0 ) {
|
---|
3357 | $neg = -1.0;
|
---|
3358 | $aVal = -$aVal;
|
---|
3359 | }
|
---|
3360 |
|
---|
3361 | $l = floor(log10($aVal));
|
---|
3362 | $a = sprintf("%0.".$aPrecision."f",round($aVal / pow(10,$l),$aPrecision));
|
---|
3363 | $a *= $neg;
|
---|
3364 | if( $this->iSimple && ($a == 1 || $a==-1) ) $a = '';
|
---|
3365 |
|
---|
3366 | if( $a != '' ) {
|
---|
3367 | $this->t = $a.' * 10';
|
---|
3368 | }
|
---|
3369 | else {
|
---|
3370 | if( $neg == 1 ) {
|
---|
3371 | $this->t = '10';
|
---|
3372 | }
|
---|
3373 | else {
|
---|
3374 | $this->t = '-10';
|
---|
3375 | }
|
---|
3376 | }
|
---|
3377 | $this->iSuper = $l;
|
---|
3378 | }
|
---|
3379 |
|
---|
3380 | function Set($aTxt,$aSuper='') {
|
---|
3381 | $this->t = $aTxt;
|
---|
3382 | $this->iSuper = $aSuper;
|
---|
3383 | }
|
---|
3384 |
|
---|
3385 | function SetSuperFont($aFontFam,$aFontStyle=FS_NORMAL,$aFontSize=8) {
|
---|
3386 | $this->sfont_family = $aFontFam;
|
---|
3387 | $this->sfont_style = $aFontStyle;
|
---|
3388 | $this->sfont_size = $aFontSize;
|
---|
3389 | }
|
---|
3390 |
|
---|
3391 | // Total width of text
|
---|
3392 | function GetWidth($aImg) {
|
---|
3393 | $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);
|
---|
3394 | $w = $aImg->GetTextWidth($this->t);
|
---|
3395 | $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size);
|
---|
3396 | $w += $aImg->GetTextWidth($this->iSuper);
|
---|
3397 | $w += $this->iSuperMargin;
|
---|
3398 | return $w;
|
---|
3399 | }
|
---|
3400 |
|
---|
3401 | // Hight of font (approximate the height of the text)
|
---|
3402 | function GetFontHeight($aImg) {
|
---|
3403 | $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);
|
---|
3404 | $h = $aImg->GetFontHeight();
|
---|
3405 | $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size);
|
---|
3406 | $h += $aImg->GetFontHeight();
|
---|
3407 | return $h;
|
---|
3408 | }
|
---|
3409 |
|
---|
3410 | // Hight of text
|
---|
3411 | function GetTextHeight($aImg) {
|
---|
3412 | $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);
|
---|
3413 | $h = $aImg->GetTextHeight($this->t);
|
---|
3414 | $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size);
|
---|
3415 | $h += $aImg->GetTextHeight($this->iSuper);
|
---|
3416 | return $h;
|
---|
3417 | }
|
---|
3418 |
|
---|
3419 | function Stroke($aImg,$ax=-1,$ay=-1) {
|
---|
3420 |
|
---|
3421 | // To position the super script correctly we need different
|
---|
3422 | // cases to handle the alignmewnt specified since that will
|
---|
3423 | // determine how we can interpret the x,y coordinates
|
---|
3424 |
|
---|
3425 | $w = parent::GetWidth($aImg);
|
---|
3426 | $h = parent::GetTextHeight($aImg);
|
---|
3427 | switch( $this->valign ) {
|
---|
3428 | case 'top':
|
---|
3429 | $sy = $this->y;
|
---|
3430 | break;
|
---|
3431 | case 'center':
|
---|
3432 | $sy = $this->y - $h/2;
|
---|
3433 | break;
|
---|
3434 | case 'bottom':
|
---|
3435 | $sy = $this->y - $h;
|
---|
3436 | break;
|
---|
3437 | default:
|
---|
3438 | JpGraphError::RaiseL(25052);//('PANIC: Internal error in SuperScript::Stroke(). Unknown vertical alignment for text');
|
---|
3439 | break;
|
---|
3440 | }
|
---|
3441 |
|
---|
3442 | switch( $this->halign ) {
|
---|
3443 | case 'left':
|
---|
3444 | $sx = $this->x + $w;
|
---|
3445 | break;
|
---|
3446 | case 'center':
|
---|
3447 | $sx = $this->x + $w/2;
|
---|
3448 | break;
|
---|
3449 | case 'right':
|
---|
3450 | $sx = $this->x;
|
---|
3451 | break;
|
---|
3452 | default:
|
---|
3453 | JpGraphError::RaiseL(25053);//('PANIC: Internal error in SuperScript::Stroke(). Unknown horizontal alignment for text');
|
---|
3454 | break;
|
---|
3455 | }
|
---|
3456 |
|
---|
3457 | $sx += $this->iSuperMargin;
|
---|
3458 | $sy += $this->iVertOverlap;
|
---|
3459 |
|
---|
3460 | // Should we automatically determine the font or
|
---|
3461 | // has the user specified it explicetly?
|
---|
3462 | if( $this->sfont_family == '' ) {
|
---|
3463 | if( $this->font_family <= FF_FONT2 ) {
|
---|
3464 | if( $this->font_family == FF_FONT0 ) {
|
---|
3465 | $sff = FF_FONT0;
|
---|
3466 | }
|
---|
3467 | elseif( $this->font_family == FF_FONT1 ) {
|
---|
3468 | if( $this->font_style == FS_NORMAL ) {
|
---|
3469 | $sff = FF_FONT0;
|
---|
3470 | }
|
---|
3471 | else {
|
---|
3472 | $sff = FF_FONT1;
|
---|
3473 | }
|
---|
3474 | }
|
---|
3475 | else {
|
---|
3476 | $sff = FF_FONT1;
|
---|
3477 | }
|
---|
3478 | $sfs = $this->font_style;
|
---|
3479 | $sfz = $this->font_size;
|
---|
3480 | }
|
---|
3481 | else {
|
---|
3482 | // TTF fonts
|
---|
3483 | $sff = $this->font_family;
|
---|
3484 | $sfs = $this->font_style;
|
---|
3485 | $sfz = floor($this->font_size*$this->iSuperScale);
|
---|
3486 | if( $sfz < 8 ) $sfz = 8;
|
---|
3487 | }
|
---|
3488 | $this->sfont_family = $sff;
|
---|
3489 | $this->sfont_style = $sfs;
|
---|
3490 | $this->sfont_size = $sfz;
|
---|
3491 | }
|
---|
3492 | else {
|
---|
3493 | $sff = $this->sfont_family;
|
---|
3494 | $sfs = $this->sfont_style;
|
---|
3495 | $sfz = $this->sfont_size;
|
---|
3496 | }
|
---|
3497 |
|
---|
3498 | parent::Stroke($aImg,$ax,$ay);
|
---|
3499 |
|
---|
3500 | // For the builtin fonts we need to reduce the margins
|
---|
3501 | // since the bounding bx reported for the builtin fonts
|
---|
3502 | // are much larger than for the TTF fonts.
|
---|
3503 | if( $sff <= FF_FONT2 ) {
|
---|
3504 | $sx -= 2;
|
---|
3505 | $sy += 3;
|
---|
3506 | }
|
---|
3507 |
|
---|
3508 | $aImg->SetTextAlign('left','bottom');
|
---|
3509 | $aImg->SetFont($sff,$sfs,$sfz);
|
---|
3510 | $aImg->PushColor($this->color);
|
---|
3511 | $aImg->StrokeText($sx,$sy,$this->iSuper,$this->iSDir,'left');
|
---|
3512 | $aImg->PopColor();
|
---|
3513 | }
|
---|
3514 | }
|
---|
3515 |
|
---|
3516 |
|
---|
3517 | //===================================================
|
---|
3518 | // CLASS Grid
|
---|
3519 | // Description: responsible for drawing grid lines in graph
|
---|
3520 | //===================================================
|
---|
3521 | class Grid {
|
---|
3522 | protected $img;
|
---|
3523 | protected $scale;
|
---|
3524 | protected $majorcolor='#CCCCCC',$minorcolor='#DDDDDD';
|
---|
3525 | protected $majortype='solid',$minortype='solid';
|
---|
3526 | protected $show=false, $showMinor=false,$majorweight=1,$minorweight=1;
|
---|
3527 | protected $fill=false,$fillcolor=array('#EFEFEF','#BBCCFF');
|
---|
3528 |
|
---|
3529 | function __construct($aAxis) {
|
---|
3530 | $this->scale = $aAxis->scale;
|
---|
3531 | $this->img = $aAxis->img;
|
---|
3532 | }
|
---|
3533 |
|
---|
3534 | function SetColor($aMajColor,$aMinColor=false) {
|
---|
3535 | $this->majorcolor=$aMajColor;
|
---|
3536 | if( $aMinColor === false ) {
|
---|
3537 | $aMinColor = $aMajColor ;
|
---|
3538 | }
|
---|
3539 | $this->minorcolor = $aMinColor;
|
---|
3540 | }
|
---|
3541 |
|
---|
3542 | function SetWeight($aMajorWeight,$aMinorWeight=1) {
|
---|
3543 | $this->majorweight=$aMajorWeight;
|
---|
3544 | $this->minorweight=$aMinorWeight;
|
---|
3545 | }
|
---|
3546 |
|
---|
3547 | // Specify if grid should be dashed, dotted or solid
|
---|
3548 | function SetLineStyle($aMajorType,$aMinorType='solid') {
|
---|
3549 | $this->majortype = $aMajorType;
|
---|
3550 | $this->minortype = $aMinorType;
|
---|
3551 | }
|
---|
3552 |
|
---|
3553 | function SetStyle($aMajorType,$aMinorType='solid') {
|
---|
3554 | $this->SetLineStyle($aMajorType,$aMinorType);
|
---|
3555 | }
|
---|
3556 |
|
---|
3557 | // Decide if both major and minor grid should be displayed
|
---|
3558 | function Show($aShowMajor=true,$aShowMinor=false) {
|
---|
3559 | $this->show=$aShowMajor;
|
---|
3560 | $this->showMinor=$aShowMinor;
|
---|
3561 | }
|
---|
3562 |
|
---|
3563 | function SetFill($aFlg=true,$aColor1='lightgray',$aColor2='lightblue') {
|
---|
3564 | $this->fill = $aFlg;
|
---|
3565 | $this->fillcolor = array( $aColor1, $aColor2 );
|
---|
3566 | }
|
---|
3567 |
|
---|
3568 | // Display the grid
|
---|
3569 | function Stroke() {
|
---|
3570 | if( $this->showMinor && !$this->scale->textscale ) {
|
---|
3571 | $this->DoStroke($this->scale->ticks->ticks_pos,$this->minortype,$this->minorcolor,$this->minorweight);
|
---|
3572 | $this->DoStroke($this->scale->ticks->maj_ticks_pos,$this->majortype,$this->majorcolor,$this->majorweight);
|
---|
3573 | }
|
---|
3574 | else {
|
---|
3575 | $this->DoStroke($this->scale->ticks->maj_ticks_pos,$this->majortype,$this->majorcolor,$this->majorweight);
|
---|
3576 | }
|
---|
3577 | }
|
---|
3578 |
|
---|
3579 | //--------------
|
---|
3580 | // Private methods
|
---|
3581 | // Draw the grid
|
---|
3582 | function DoStroke($aTicksPos,$aType,$aColor,$aWeight) {
|
---|
3583 | if( !$this->show ) return;
|
---|
3584 | $nbrgrids = count($aTicksPos);
|
---|
3585 |
|
---|
3586 | if( $this->scale->type == 'y' ) {
|
---|
3587 | $xl=$this->img->left_margin;
|
---|
3588 | $xr=$this->img->width-$this->img->right_margin;
|
---|
3589 |
|
---|
3590 | if( $this->fill ) {
|
---|
3591 | // Draw filled areas
|
---|
3592 | $y2 = !empty($aTicksPos) ? $aTicksPos[0] : null;
|
---|
3593 | $i=1;
|
---|
3594 | while( $i < $nbrgrids ) {
|
---|
3595 | $y1 = $y2;
|
---|
3596 | $y2 = $aTicksPos[$i++];
|
---|
3597 | $this->img->SetColor($this->fillcolor[$i & 1]);
|
---|
3598 | $this->img->FilledRectangle($xl,$y1,$xr,$y2);
|
---|
3599 | }
|
---|
3600 | }
|
---|
3601 |
|
---|
3602 | $this->img->SetColor($aColor);
|
---|
3603 | $this->img->SetLineWeight($aWeight);
|
---|
3604 |
|
---|
3605 | // Draw grid lines
|
---|
3606 | switch( $aType ) {
|
---|
3607 | case 'solid': $style = LINESTYLE_SOLID; break;
|
---|
3608 | case 'dotted': $style = LINESTYLE_DOTTED; break;
|
---|
3609 | case 'dashed': $style = LINESTYLE_DASHED; break;
|
---|
3610 | case 'longdashed': $style = LINESTYLE_LONGDASH; break;
|
---|
3611 | default:
|
---|
3612 | $style = LINESTYLE_SOLID; break;
|
---|
3613 | }
|
---|
3614 |
|
---|
3615 | for($i=0; $i < $nbrgrids; ++$i) {
|
---|
3616 | $y=$aTicksPos[$i];
|
---|
3617 | $this->img->StyleLine($xl,$y,$xr,$y,$style,true);
|
---|
3618 | }
|
---|
3619 | }
|
---|
3620 | elseif( $this->scale->type == 'x' ) {
|
---|
3621 | $yu=$this->img->top_margin;
|
---|
3622 | $yl=$this->img->height-$this->img->bottom_margin;
|
---|
3623 | $limit=$this->img->width-$this->img->right_margin;
|
---|
3624 |
|
---|
3625 | if( $this->fill ) {
|
---|
3626 | // Draw filled areas
|
---|
3627 | $x2 = $aTicksPos[0];
|
---|
3628 | $i=1;
|
---|
3629 | while( $i < $nbrgrids ) {
|
---|
3630 | $x1 = $x2;
|
---|
3631 | $x2 = min($aTicksPos[$i++],$limit) ;
|
---|
3632 | $this->img->SetColor($this->fillcolor[$i & 1]);
|
---|
3633 | $this->img->FilledRectangle($x1,$yu,$x2,$yl);
|
---|
3634 | }
|
---|
3635 | }
|
---|
3636 |
|
---|
3637 | $this->img->SetColor($aColor);
|
---|
3638 | $this->img->SetLineWeight($aWeight);
|
---|
3639 |
|
---|
3640 | // We must also test for limit since we might have
|
---|
3641 | // an offset and the number of ticks is calculated with
|
---|
3642 | // assumption offset==0 so we might end up drawing one
|
---|
3643 | // to many gridlines
|
---|
3644 | $i=0;
|
---|
3645 | $x=$aTicksPos[$i];
|
---|
3646 | while( $i<count($aTicksPos) && ($x=$aTicksPos[$i]) <= $limit ) {
|
---|
3647 | if ( $aType == 'solid' ) $this->img->Line($x,$yl,$x,$yu);
|
---|
3648 | elseif( $aType == 'dotted' ) $this->img->DashedLineForGrid($x,$yl,$x,$yu,1,6);
|
---|
3649 | elseif( $aType == 'dashed' ) $this->img->DashedLineForGrid($x,$yl,$x,$yu,2,4);
|
---|
3650 | elseif( $aType == 'longdashed' ) $this->img->DashedLineForGrid($x,$yl,$x,$yu,8,6);
|
---|
3651 | ++$i;
|
---|
3652 | }
|
---|
3653 | }
|
---|
3654 | else {
|
---|
3655 | JpGraphError::RaiseL(25054,$this->scale->type);//('Internal error: Unknown grid axis ['.$this->scale->type.']');
|
---|
3656 | }
|
---|
3657 | return true;
|
---|
3658 | }
|
---|
3659 | } // Class
|
---|
3660 |
|
---|
3661 | //===================================================
|
---|
3662 | // CLASS Axis
|
---|
3663 | // Description: Defines X and Y axis. Notes that at the
|
---|
3664 | // moment the code is not really good since the axis on
|
---|
3665 | // several occasion must know wheter it's an X or Y axis.
|
---|
3666 | // This was a design decision to make the code easier to
|
---|
3667 | // follow.
|
---|
3668 | //===================================================
|
---|
3669 | class AxisPrototype {
|
---|
3670 | public $scale=null;
|
---|
3671 | public $img=null;
|
---|
3672 | public $hide=false,$hide_labels=false;
|
---|
3673 | public $title=null;
|
---|
3674 | public $font_family=FF_DEFAULT,$font_style=FS_NORMAL,$font_size=8,$label_angle=0;
|
---|
3675 | public $tick_step=1;
|
---|
3676 | public $pos = false;
|
---|
3677 | public $ticks_label = array();
|
---|
3678 |
|
---|
3679 | protected $weight=1;
|
---|
3680 | protected $color=array(0,0,0),$label_color=array(0,0,0);
|
---|
3681 | protected $ticks_label_colors=null;
|
---|
3682 | protected $show_first_label=true,$show_last_label=true;
|
---|
3683 | protected $label_step=1; // Used by a text axis to specify what multiple of major steps
|
---|
3684 | // should be labeled.
|
---|
3685 | protected $labelPos=0; // Which side of the axis should the labels be?
|
---|
3686 | protected $title_adjust,$title_margin,$title_side=SIDE_LEFT;
|
---|
3687 | protected $tick_label_margin=5;
|
---|
3688 | protected $label_halign = '',$label_valign = '', $label_para_align='left';
|
---|
3689 | protected $hide_line=false;
|
---|
3690 | protected $iDeltaAbsPos=0;
|
---|
3691 |
|
---|
3692 | function __construct($img,$aScale,$color = array(0,0,0)) {
|
---|
3693 | $this->img = $img;
|
---|
3694 | $this->scale = $aScale;
|
---|
3695 | $this->color = $color;
|
---|
3696 | $this->title=new Text('');
|
---|
3697 |
|
---|
3698 | if( $aScale->type == 'y' ) {
|
---|
3699 | $this->title_margin = 25;
|
---|
3700 | $this->title_adjust = 'middle';
|
---|
3701 | $this->title->SetOrientation(90);
|
---|
3702 | $this->tick_label_margin=7;
|
---|
3703 | $this->labelPos=SIDE_LEFT;
|
---|
3704 | }
|
---|
3705 | else {
|
---|
3706 | $this->title_margin = 5;
|
---|
3707 | $this->title_adjust = 'high';
|
---|
3708 | $this->title->SetOrientation(0);
|
---|
3709 | $this->tick_label_margin=5;
|
---|
3710 | $this->labelPos=SIDE_DOWN;
|
---|
3711 | $this->title_side=SIDE_DOWN;
|
---|
3712 | }
|
---|
3713 | }
|
---|
3714 |
|
---|
3715 | function SetLabelFormat($aFormStr) {
|
---|
3716 | $this->scale->ticks->SetLabelFormat($aFormStr);
|
---|
3717 | }
|
---|
3718 |
|
---|
3719 | function SetLabelFormatString($aFormStr,$aDate=false) {
|
---|
3720 | $this->scale->ticks->SetLabelFormat($aFormStr,$aDate);
|
---|
3721 | }
|
---|
3722 |
|
---|
3723 | function SetLabelFormatCallback($aFuncName) {
|
---|
3724 | $this->scale->ticks->SetFormatCallback($aFuncName);
|
---|
3725 | }
|
---|
3726 |
|
---|
3727 | function SetLabelAlign($aHAlign,$aVAlign='top',$aParagraphAlign='left') {
|
---|
3728 | $this->label_halign = $aHAlign;
|
---|
3729 | $this->label_valign = $aVAlign;
|
---|
3730 | $this->label_para_align = $aParagraphAlign;
|
---|
3731 | }
|
---|
3732 |
|
---|
3733 | // Don't display the first label
|
---|
3734 | function HideFirstTickLabel($aShow=false) {
|
---|
3735 | $this->show_first_label=$aShow;
|
---|
3736 | }
|
---|
3737 |
|
---|
3738 | function HideLastTickLabel($aShow=false) {
|
---|
3739 | $this->show_last_label=$aShow;
|
---|
3740 | }
|
---|
3741 |
|
---|
3742 | // Manually specify the major and (optional) minor tick position and labels
|
---|
3743 | function SetTickPositions($aMajPos,$aMinPos=NULL,$aLabels=NULL) {
|
---|
3744 | $this->scale->ticks->SetTickPositions($aMajPos,$aMinPos,$aLabels);
|
---|
3745 | }
|
---|
3746 |
|
---|
3747 | // Manually specify major tick positions and optional labels
|
---|
3748 | function SetMajTickPositions($aMajPos,$aLabels=NULL) {
|
---|
3749 | $this->scale->ticks->SetTickPositions($aMajPos,NULL,$aLabels);
|
---|
3750 | }
|
---|
3751 |
|
---|
3752 | // Hide minor or major tick marks
|
---|
3753 | function HideTicks($aHideMinor=true,$aHideMajor=true) {
|
---|
3754 | $this->scale->ticks->SupressMinorTickMarks($aHideMinor);
|
---|
3755 | $this->scale->ticks->SupressTickMarks($aHideMajor);
|
---|
3756 | }
|
---|
3757 |
|
---|
3758 | // Hide zero label
|
---|
3759 | function HideZeroLabel($aFlag=true) {
|
---|
3760 | $this->scale->ticks->SupressZeroLabel();
|
---|
3761 | }
|
---|
3762 |
|
---|
3763 | function HideFirstLastLabel() {
|
---|
3764 | // The two first calls to ticks method will supress
|
---|
3765 | // automatically generated scale values. However, that
|
---|
3766 | // will not affect manually specified value, e.g text-scales.
|
---|
3767 | // therefor we also make a kludge here to supress manually
|
---|
3768 | // specified scale labels.
|
---|
3769 | $this->scale->ticks->SupressLast();
|
---|
3770 | $this->scale->ticks->SupressFirst();
|
---|
3771 | $this->show_first_label = false;
|
---|
3772 | $this->show_last_label = false;
|
---|
3773 | }
|
---|
3774 |
|
---|
3775 | // Hide the axis
|
---|
3776 | function Hide($aHide=true) {
|
---|
3777 | $this->hide=$aHide;
|
---|
3778 | }
|
---|
3779 |
|
---|
3780 | // Hide the actual axis-line, but still print the labels
|
---|
3781 | function HideLine($aHide=true) {
|
---|
3782 | $this->hide_line = $aHide;
|
---|
3783 | }
|
---|
3784 |
|
---|
3785 | function HideLabels($aHide=true) {
|
---|
3786 | $this->hide_labels = $aHide;
|
---|
3787 | }
|
---|
3788 |
|
---|
3789 | // Weight of axis
|
---|
3790 | function SetWeight($aWeight) {
|
---|
3791 | $this->weight = $aWeight;
|
---|
3792 | }
|
---|
3793 |
|
---|
3794 | // Axis color
|
---|
3795 | function SetColor($aColor,$aLabelColor=false) {
|
---|
3796 | $this->color = $aColor;
|
---|
3797 | if( !$aLabelColor ) $this->label_color = $aColor;
|
---|
3798 | else $this->label_color = $aLabelColor;
|
---|
3799 | }
|
---|
3800 |
|
---|
3801 | // Title on axis
|
---|
3802 | function SetTitle($aTitle,$aAdjustAlign='high') {
|
---|
3803 | $this->title->Set($aTitle);
|
---|
3804 | $this->title_adjust=$aAdjustAlign;
|
---|
3805 | }
|
---|
3806 |
|
---|
3807 | // Specify distance from the axis
|
---|
3808 | function SetTitleMargin($aMargin) {
|
---|
3809 | $this->title_margin=$aMargin;
|
---|
3810 | }
|
---|
3811 |
|
---|
3812 | // Which side of the axis should the axis title be?
|
---|
3813 | function SetTitleSide($aSideOfAxis) {
|
---|
3814 | $this->title_side = $aSideOfAxis;
|
---|
3815 | }
|
---|
3816 |
|
---|
3817 | function SetTickSide($aDir) {
|
---|
3818 | $this->scale->ticks->SetSide($aDir);
|
---|
3819 | }
|
---|
3820 |
|
---|
3821 | function SetTickSize($aMajSize,$aMinSize=3) {
|
---|
3822 | $this->scale->ticks->SetSize($aMajSize,$aMinSize=3);
|
---|
3823 | }
|
---|
3824 |
|
---|
3825 | // Specify text labels for the ticks. One label for each data point
|
---|
3826 | function SetTickLabels($aLabelArray,$aLabelColorArray=null) {
|
---|
3827 | $this->ticks_label = $aLabelArray;
|
---|
3828 | $this->ticks_label_colors = $aLabelColorArray;
|
---|
3829 | }
|
---|
3830 |
|
---|
3831 | function SetLabelMargin($aMargin) {
|
---|
3832 | $this->tick_label_margin=$aMargin;
|
---|
3833 | }
|
---|
3834 |
|
---|
3835 | // Specify that every $step of the ticks should be displayed starting
|
---|
3836 | // at $start
|
---|
3837 | function SetTextTickInterval($aStep,$aStart=0) {
|
---|
3838 | $this->scale->ticks->SetTextLabelStart($aStart);
|
---|
3839 | $this->tick_step=$aStep;
|
---|
3840 | }
|
---|
3841 |
|
---|
3842 | // Specify that every $step tick mark should have a label
|
---|
3843 | // should be displayed starting
|
---|
3844 | function SetTextLabelInterval($aStep) {
|
---|
3845 | if( $aStep < 1 ) {
|
---|
3846 | JpGraphError::RaiseL(25058);//(" Text label interval must be specified >= 1.");
|
---|
3847 | }
|
---|
3848 | $this->label_step=$aStep;
|
---|
3849 | }
|
---|
3850 |
|
---|
3851 | function SetLabelSide($aSidePos) {
|
---|
3852 | $this->labelPos=$aSidePos;
|
---|
3853 | }
|
---|
3854 |
|
---|
3855 | // Set the font
|
---|
3856 | function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) {
|
---|
3857 | $this->font_family = $aFamily;
|
---|
3858 | $this->font_style = $aStyle;
|
---|
3859 | $this->font_size = $aSize;
|
---|
3860 | }
|
---|
3861 |
|
---|
3862 | // Position for axis line on the "other" scale
|
---|
3863 | function SetPos($aPosOnOtherScale) {
|
---|
3864 | $this->pos=$aPosOnOtherScale;
|
---|
3865 | }
|
---|
3866 |
|
---|
3867 | // Set the position of the axis to be X-pixels delta to the right
|
---|
3868 | // of the max X-position (used to position the multiple Y-axis)
|
---|
3869 | function SetPosAbsDelta($aDelta) {
|
---|
3870 | $this->iDeltaAbsPos=$aDelta;
|
---|
3871 | }
|
---|
3872 |
|
---|
3873 | // Specify the angle for the tick labels
|
---|
3874 | function SetLabelAngle($aAngle) {
|
---|
3875 | $this->label_angle = $aAngle;
|
---|
3876 | }
|
---|
3877 |
|
---|
3878 | } // Class
|
---|
3879 |
|
---|
3880 |
|
---|
3881 | //===================================================
|
---|
3882 | // CLASS Axis
|
---|
3883 | // Description: Defines X and Y axis. Notes that at the
|
---|
3884 | // moment the code is not really good since the axis on
|
---|
3885 | // several occasion must know wheter it's an X or Y axis.
|
---|
3886 | // This was a design decision to make the code easier to
|
---|
3887 | // follow.
|
---|
3888 | //===================================================
|
---|
3889 | class Axis extends AxisPrototype {
|
---|
3890 |
|
---|
3891 | function __construct($img,$aScale,$color='black') {
|
---|
3892 | parent::__construct($img,$aScale,$color);
|
---|
3893 | }
|
---|
3894 |
|
---|
3895 | // Stroke the axis.
|
---|
3896 | function Stroke($aOtherAxisScale,$aStrokeLabels=true) {
|
---|
3897 | if( $this->hide )
|
---|
3898 | return;
|
---|
3899 | if( is_numeric($this->pos) ) {
|
---|
3900 | $pos=$aOtherAxisScale->Translate($this->pos);
|
---|
3901 | }
|
---|
3902 | else { // Default to minimum of other scale if pos not set
|
---|
3903 | if( ($aOtherAxisScale->GetMinVal() >= 0 && $this->pos==false) || $this->pos == 'min' ) {
|
---|
3904 | $pos = $aOtherAxisScale->scale_abs[0];
|
---|
3905 | }
|
---|
3906 | elseif($this->pos == "max") {
|
---|
3907 | $pos = $aOtherAxisScale->scale_abs[1];
|
---|
3908 | }
|
---|
3909 | else { // If negative set x-axis at 0
|
---|
3910 | $this->pos=0;
|
---|
3911 | $pos=$aOtherAxisScale->Translate(0);
|
---|
3912 | }
|
---|
3913 | }
|
---|
3914 |
|
---|
3915 | $pos += $this->iDeltaAbsPos;
|
---|
3916 | $this->img->SetLineWeight($this->weight);
|
---|
3917 | $this->img->SetColor($this->color);
|
---|
3918 | $this->img->SetFont($this->font_family,$this->font_style,$this->font_size);
|
---|
3919 |
|
---|
3920 | if( $this->scale->type == "x" ) {
|
---|
3921 | if( !$this->hide_line ) {
|
---|
3922 | // Stroke X-axis
|
---|
3923 | $this->img->FilledRectangle(
|
---|
3924 | $this->img->left_margin,
|
---|
3925 | $pos,
|
---|
3926 | $this->img->width - $this->img->right_margin,
|
---|
3927 | $pos + $this->weight-1
|
---|
3928 | );
|
---|
3929 | }
|
---|
3930 | if( $this->title_side == SIDE_DOWN ) {
|
---|
3931 | $y = $pos + $this->img->GetFontHeight() + $this->title_margin + $this->title->margin;
|
---|
3932 | $yalign = 'top';
|
---|
3933 | }
|
---|
3934 | else {
|
---|
3935 | $y = $pos - $this->img->GetFontHeight() - $this->title_margin - $this->title->margin;
|
---|
3936 | $yalign = 'bottom';
|
---|
3937 | }
|
---|
3938 |
|
---|
3939 | if( $this->title_adjust=='high' ) {
|
---|
3940 | $this->title->SetPos($this->img->width-$this->img->right_margin,$y,'right',$yalign);
|
---|
3941 | }
|
---|
3942 | elseif( $this->title_adjust=='middle' || $this->title_adjust=='center' ) {
|
---|
3943 | $this->title->SetPos(($this->img->width-$this->img->left_margin-$this->img->right_margin)/2+$this->img->left_margin,$y,'center',$yalign);
|
---|
3944 | }
|
---|
3945 | elseif($this->title_adjust=='low') {
|
---|
3946 | $this->title->SetPos($this->img->left_margin,$y,'left',$yalign);
|
---|
3947 | }
|
---|
3948 | else {
|
---|
3949 | JpGraphError::RaiseL(25060,$this->title_adjust);//('Unknown alignment specified for X-axis title. ('.$this->title_adjust.')');
|
---|
3950 | }
|
---|
3951 | }
|
---|
3952 | elseif( $this->scale->type == "y" ) {
|
---|
3953 | // Add line weight to the height of the axis since
|
---|
3954 | // the x-axis could have a width>1 and we want the axis to fit nicely together.
|
---|
3955 | if( !$this->hide_line ) {
|
---|
3956 | // Stroke Y-axis
|
---|
3957 | $this->img->FilledRectangle(
|
---|
3958 | $pos - $this->weight + 1,
|
---|
3959 | $this->img->top_margin,
|
---|
3960 | $pos,
|
---|
3961 | $this->img->height - $this->img->bottom_margin + $this->weight - 1
|
---|
3962 | );
|
---|
3963 | }
|
---|
3964 |
|
---|
3965 | $x=$pos ;
|
---|
3966 | if( $this->title_side == SIDE_LEFT ) {
|
---|
3967 | $x -= $this->title_margin;
|
---|
3968 | $x -= $this->title->margin;
|
---|
3969 | $halign = 'right';
|
---|
3970 | }
|
---|
3971 | else {
|
---|
3972 | $x += $this->title_margin;
|
---|
3973 | $x += $this->title->margin;
|
---|
3974 | $halign = 'left';
|
---|
3975 | }
|
---|
3976 | // If the user has manually specified an hor. align
|
---|
3977 | // then we override the automatic settings with this
|
---|
3978 | // specifed setting. Since default is 'left' we compare
|
---|
3979 | // with that. (This means a manually set 'left' align
|
---|
3980 | // will have no effect.)
|
---|
3981 | if( $this->title->halign != 'left' ) {
|
---|
3982 | $halign = $this->title->halign;
|
---|
3983 | }
|
---|
3984 | if( $this->title_adjust == 'high' ) {
|
---|
3985 | $this->title->SetPos($x,$this->img->top_margin,$halign,'top');
|
---|
3986 | }
|
---|
3987 | elseif($this->title_adjust=='middle' || $this->title_adjust=='center') {
|
---|
3988 | $this->title->SetPos($x,($this->img->height-$this->img->top_margin-$this->img->bottom_margin)/2+$this->img->top_margin,$halign,"center");
|
---|
3989 | }
|
---|
3990 | elseif($this->title_adjust=='low') {
|
---|
3991 | $this->title->SetPos($x,$this->img->height-$this->img->bottom_margin,$halign,'bottom');
|
---|
3992 | }
|
---|
3993 | else {
|
---|
3994 | JpGraphError::RaiseL(25061,$this->title_adjust);//('Unknown alignment specified for Y-axis title. ('.$this->title_adjust.')');
|
---|
3995 | }
|
---|
3996 | }
|
---|
3997 | $this->scale->ticks->Stroke($this->img,$this->scale,$pos);
|
---|
3998 | if( $aStrokeLabels ) {
|
---|
3999 | if( !$this->hide_labels ) {
|
---|
4000 | $this->StrokeLabels($pos);
|
---|
4001 | }
|
---|
4002 | $this->title->Stroke($this->img);
|
---|
4003 | }
|
---|
4004 | }
|
---|
4005 |
|
---|
4006 | //---------------
|
---|
4007 | // PRIVATE METHODS
|
---|
4008 | // Draw all the tick labels on major tick marks
|
---|
4009 | function StrokeLabels($aPos,$aMinor=false,$aAbsLabel=false) {
|
---|
4010 |
|
---|
4011 | if( is_array($this->label_color) && count($this->label_color) > 3 ) {
|
---|
4012 | $this->ticks_label_colors = $this->label_color;
|
---|
4013 | $this->img->SetColor($this->label_color[0]);
|
---|
4014 | }
|
---|
4015 | else {
|
---|
4016 | $this->img->SetColor($this->label_color);
|
---|
4017 | }
|
---|
4018 | $this->img->SetFont($this->font_family,$this->font_style,$this->font_size);
|
---|
4019 | $yoff=$this->img->GetFontHeight()/2;
|
---|
4020 |
|
---|
4021 | // Only draw labels at major tick marks
|
---|
4022 | $nbr = count($this->scale->ticks->maj_ticks_label);
|
---|
4023 |
|
---|
4024 | // We have the option to not-display the very first mark
|
---|
4025 | // (Usefull when the first label might interfere with another
|
---|
4026 | // axis.)
|
---|
4027 | $i = $this->show_first_label ? 0 : 1 ;
|
---|
4028 | if( !$this->show_last_label ) {
|
---|
4029 | --$nbr;
|
---|
4030 | }
|
---|
4031 | // Now run through all labels making sure we don't overshoot the end
|
---|
4032 | // of the scale.
|
---|
4033 | $ncolor=0;
|
---|
4034 | if( isset($this->ticks_label_colors) ) {
|
---|
4035 | $ncolor=count($this->ticks_label_colors);
|
---|
4036 | }
|
---|
4037 | while( $i < $nbr ) {
|
---|
4038 | // $tpos holds the absolute text position for the label
|
---|
4039 | $tpos=$this->scale->ticks->maj_ticklabels_pos[$i];
|
---|
4040 |
|
---|
4041 | // Note. the $limit is only used for the x axis since we
|
---|
4042 | // might otherwise overshoot if the scale has been centered
|
---|
4043 | // This is due to us "loosing" the last tick mark if we center.
|
---|
4044 | if( $this->scale->type == 'x' && $tpos > $this->img->width-$this->img->right_margin+1 ) {
|
---|
4045 | return;
|
---|
4046 | }
|
---|
4047 | // we only draw every $label_step label
|
---|
4048 | if( ($i % $this->label_step)==0 ) {
|
---|
4049 |
|
---|
4050 | // Set specific label color if specified
|
---|
4051 | if( $ncolor > 0 ) {
|
---|
4052 | $this->img->SetColor($this->ticks_label_colors[$i % $ncolor]);
|
---|
4053 | }
|
---|
4054 |
|
---|
4055 | // If the label has been specified use that and in other case
|
---|
4056 | // just label the mark with the actual scale value
|
---|
4057 | $m=$this->scale->ticks->GetMajor();
|
---|
4058 |
|
---|
4059 | // ticks_label has an entry for each data point and is the array
|
---|
4060 | // that holds the labels set by the user. If the user hasn't
|
---|
4061 | // specified any values we use whats in the automatically asigned
|
---|
4062 | // labels in the maj_ticks_label
|
---|
4063 | if( isset($this->ticks_label[$i*$m]) ) {
|
---|
4064 | $label=$this->ticks_label[$i*$m];
|
---|
4065 | }
|
---|
4066 | else {
|
---|
4067 | if( $aAbsLabel ) {
|
---|
4068 | $label=abs($this->scale->ticks->maj_ticks_label[$i]);
|
---|
4069 | }
|
---|
4070 | else {
|
---|
4071 | $label=$this->scale->ticks->maj_ticks_label[$i];
|
---|
4072 | }
|
---|
4073 |
|
---|
4074 | // We number the scale from 1 and not from 0 so increase by one
|
---|
4075 | if( $this->scale->textscale &&
|
---|
4076 | $this->scale->ticks->label_formfunc == '' &&
|
---|
4077 | ! $this->scale->ticks->HaveManualLabels() ) {
|
---|
4078 |
|
---|
4079 | ++$label;
|
---|
4080 |
|
---|
4081 | }
|
---|
4082 | }
|
---|
4083 |
|
---|
4084 | if( $this->scale->type == "x" ) {
|
---|
4085 | if( $this->labelPos == SIDE_DOWN ) {
|
---|
4086 | if( $this->label_angle==0 || $this->label_angle==90 ) {
|
---|
4087 | if( $this->label_halign=='' && $this->label_valign=='') {
|
---|
4088 | $this->img->SetTextAlign('center','top');
|
---|
4089 | }
|
---|
4090 | else {
|
---|
4091 | $this->img->SetTextAlign($this->label_halign,$this->label_valign);
|
---|
4092 | }
|
---|
4093 |
|
---|
4094 | }
|
---|
4095 | else {
|
---|
4096 | if( $this->label_halign=='' && $this->label_valign=='') {
|
---|
4097 | $this->img->SetTextAlign("right","top");
|
---|
4098 | }
|
---|
4099 | else {
|
---|
4100 | $this->img->SetTextAlign($this->label_halign,$this->label_valign);
|
---|
4101 | }
|
---|
4102 | }
|
---|
4103 | $this->img->StrokeText($tpos,$aPos+$this->tick_label_margin,$label,
|
---|
4104 | $this->label_angle,$this->label_para_align);
|
---|
4105 | }
|
---|
4106 | else {
|
---|
4107 | if( $this->label_angle==0 || $this->label_angle==90 ) {
|
---|
4108 | if( $this->label_halign=='' && $this->label_valign=='') {
|
---|
4109 | $this->img->SetTextAlign("center","bottom");
|
---|
4110 | }
|
---|
4111 | else {
|
---|
4112 | $this->img->SetTextAlign($this->label_halign,$this->label_valign);
|
---|
4113 | }
|
---|
4114 | }
|
---|
4115 | else {
|
---|
4116 | if( $this->label_halign=='' && $this->label_valign=='') {
|
---|
4117 | $this->img->SetTextAlign("right","bottom");
|
---|
4118 | }
|
---|
4119 | else {
|
---|
4120 | $this->img->SetTextAlign($this->label_halign,$this->label_valign);
|
---|
4121 | }
|
---|
4122 | }
|
---|
4123 | $this->img->StrokeText($tpos,$aPos-$this->tick_label_margin-1,$label,
|
---|
4124 | $this->label_angle,$this->label_para_align);
|
---|
4125 | }
|
---|
4126 | }
|
---|
4127 | else {
|
---|
4128 | // scale->type == "y"
|
---|
4129 | //if( $this->label_angle!=0 )
|
---|
4130 | //JpGraphError::Raise(" Labels at an angle are not supported on Y-axis");
|
---|
4131 | if( $this->labelPos == SIDE_LEFT ) { // To the left of y-axis
|
---|
4132 | if( $this->label_halign=='' && $this->label_valign=='') {
|
---|
4133 | $this->img->SetTextAlign("right","center");
|
---|
4134 | }
|
---|
4135 | else {
|
---|
4136 | $this->img->SetTextAlign($this->label_halign,$this->label_valign);
|
---|
4137 | }
|
---|
4138 | $this->img->StrokeText($aPos-$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align);
|
---|
4139 | }
|
---|
4140 | else { // To the right of the y-axis
|
---|
4141 | if( $this->label_halign=='' && $this->label_valign=='') {
|
---|
4142 | $this->img->SetTextAlign("left","center");
|
---|
4143 | }
|
---|
4144 | else {
|
---|
4145 | $this->img->SetTextAlign($this->label_halign,$this->label_valign);
|
---|
4146 | }
|
---|
4147 | $this->img->StrokeText($aPos+$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align);
|
---|
4148 | }
|
---|
4149 | }
|
---|
4150 | }
|
---|
4151 | ++$i;
|
---|
4152 | }
|
---|
4153 | }
|
---|
4154 |
|
---|
4155 | }
|
---|
4156 |
|
---|
4157 |
|
---|
4158 | //===================================================
|
---|
4159 | // CLASS Ticks
|
---|
4160 | // Description: Abstract base class for drawing linear and logarithmic
|
---|
4161 | // tick marks on axis
|
---|
4162 | //===================================================
|
---|
4163 | class Ticks {
|
---|
4164 | public $label_formatstr=''; // C-style format string to use for labels
|
---|
4165 | public $label_formfunc='';
|
---|
4166 | public $label_dateformatstr='';
|
---|
4167 | public $direction=1; // Should ticks be in(=1) the plot area or outside (=-1)
|
---|
4168 | public $supress_last=false,$supress_tickmarks=false,$supress_minor_tickmarks=false;
|
---|
4169 | public $maj_ticks_pos = array(), $maj_ticklabels_pos = array(),
|
---|
4170 | $ticks_pos = array(), $maj_ticks_label = array();
|
---|
4171 | public $precision;
|
---|
4172 |
|
---|
4173 | protected $minor_abs_size=3, $major_abs_size=5;
|
---|
4174 | protected $scale;
|
---|
4175 | protected $is_set=false;
|
---|
4176 | protected $supress_zerolabel=false,$supress_first=false;
|
---|
4177 | protected $mincolor='',$majcolor='';
|
---|
4178 | protected $weight=1;
|
---|
4179 | protected $label_usedateformat=FALSE;
|
---|
4180 |
|
---|
4181 | function __construct($aScale) {
|
---|
4182 | $this->scale=$aScale;
|
---|
4183 | $this->precision = -1;
|
---|
4184 | }
|
---|
4185 |
|
---|
4186 | // Set format string for automatic labels
|
---|
4187 | function SetLabelFormat($aFormatString,$aDate=FALSE) {
|
---|
4188 | $this->label_formatstr=$aFormatString;
|
---|
4189 | $this->label_usedateformat=$aDate;
|
---|
4190 | }
|
---|
4191 |
|
---|
4192 | function SetLabelDateFormat($aFormatString) {
|
---|
4193 | $this->label_dateformatstr=$aFormatString;
|
---|
4194 | }
|
---|
4195 |
|
---|
4196 | function SetFormatCallback($aCallbackFuncName) {
|
---|
4197 | $this->label_formfunc = $aCallbackFuncName;
|
---|
4198 | }
|
---|
4199 |
|
---|
4200 | // Don't display the first zero label
|
---|
4201 | function SupressZeroLabel($aFlag=true) {
|
---|
4202 | $this->supress_zerolabel=$aFlag;
|
---|
4203 | }
|
---|
4204 |
|
---|
4205 | // Don't display minor tick marks
|
---|
4206 | function SupressMinorTickMarks($aHide=true) {
|
---|
4207 | $this->supress_minor_tickmarks=$aHide;
|
---|
4208 | }
|
---|
4209 |
|
---|
4210 | // Don't display major tick marks
|
---|
4211 | function SupressTickMarks($aHide=true) {
|
---|
4212 | $this->supress_tickmarks=$aHide;
|
---|
4213 | }
|
---|
4214 |
|
---|
4215 | // Hide the first tick mark
|
---|
4216 | function SupressFirst($aHide=true) {
|
---|
4217 | $this->supress_first=$aHide;
|
---|
4218 | }
|
---|
4219 |
|
---|
4220 | // Hide the last tick mark
|
---|
4221 | function SupressLast($aHide=true) {
|
---|
4222 | $this->supress_last=$aHide;
|
---|
4223 | }
|
---|
4224 |
|
---|
4225 | // Size (in pixels) of minor tick marks
|
---|
4226 | function GetMinTickAbsSize() {
|
---|
4227 | return $this->minor_abs_size;
|
---|
4228 | }
|
---|
4229 |
|
---|
4230 | // Size (in pixels) of major tick marks
|
---|
4231 | function GetMajTickAbsSize() {
|
---|
4232 | return $this->major_abs_size;
|
---|
4233 | }
|
---|
4234 |
|
---|
4235 | function SetSize($aMajSize,$aMinSize=3) {
|
---|
4236 | $this->major_abs_size = $aMajSize;
|
---|
4237 | $this->minor_abs_size = $aMinSize;
|
---|
4238 | }
|
---|
4239 |
|
---|
4240 | // Have the ticks been specified
|
---|
4241 | function IsSpecified() {
|
---|
4242 | return $this->is_set;
|
---|
4243 | }
|
---|
4244 |
|
---|
4245 | function SetSide($aSide) {
|
---|
4246 | $this->direction=$aSide;
|
---|
4247 | }
|
---|
4248 |
|
---|
4249 | // Which side of the axis should the ticks be on
|
---|
4250 | function SetDirection($aSide=SIDE_RIGHT) {
|
---|
4251 | $this->direction=$aSide;
|
---|
4252 | }
|
---|
4253 |
|
---|
4254 | // Set colors for major and minor tick marks
|
---|
4255 | function SetMarkColor($aMajorColor,$aMinorColor='') {
|
---|
4256 | $this->SetColor($aMajorColor,$aMinorColor);
|
---|
4257 | }
|
---|
4258 |
|
---|
4259 | function SetColor($aMajorColor,$aMinorColor='') {
|
---|
4260 | $this->majcolor=$aMajorColor;
|
---|
4261 |
|
---|
4262 | // If not specified use same as major
|
---|
4263 | if( $aMinorColor == '' ) {
|
---|
4264 | $this->mincolor=$aMajorColor;
|
---|
4265 | }
|
---|
4266 | else {
|
---|
4267 | $this->mincolor=$aMinorColor;
|
---|
4268 | }
|
---|
4269 | }
|
---|
4270 |
|
---|
4271 | function SetWeight($aWeight) {
|
---|
4272 | $this->weight=$aWeight;
|
---|
4273 | }
|
---|
4274 |
|
---|
4275 | } // Class
|
---|
4276 |
|
---|
4277 | //===================================================
|
---|
4278 | // CLASS LinearTicks
|
---|
4279 | // Description: Draw linear ticks on axis
|
---|
4280 | //===================================================
|
---|
4281 | class LinearTicks extends Ticks {
|
---|
4282 | public $minor_step=1, $major_step=2;
|
---|
4283 | public $xlabel_offset=0,$xtick_offset=0;
|
---|
4284 | private $label_offset=0; // What offset should the displayed label have
|
---|
4285 | // i.e should we display 0,1,2 or 1,2,3,4 or 2,3,4 etc
|
---|
4286 | private $text_label_start=0;
|
---|
4287 | private $iManualTickPos = NULL, $iManualMinTickPos = NULL, $iManualTickLabels = NULL;
|
---|
4288 | private $iAdjustForDST = false; // If a date falls within the DST period add one hour to the diaplyed time
|
---|
4289 |
|
---|
4290 | function __construct() {
|
---|
4291 | $this->precision = -1;
|
---|
4292 | }
|
---|
4293 |
|
---|
4294 | // Return major step size in world coordinates
|
---|
4295 | function GetMajor() {
|
---|
4296 | return $this->major_step;
|
---|
4297 | }
|
---|
4298 |
|
---|
4299 | // Return minor step size in world coordinates
|
---|
4300 | function GetMinor() {
|
---|
4301 | return $this->minor_step;
|
---|
4302 | }
|
---|
4303 |
|
---|
4304 | // Set Minor and Major ticks (in world coordinates)
|
---|
4305 | function Set($aMajStep,$aMinStep=false) {
|
---|
4306 | if( $aMinStep==false ) {
|
---|
4307 | $aMinStep=$aMajStep;
|
---|
4308 | }
|
---|
4309 |
|
---|
4310 | if( $aMajStep <= 0 || $aMinStep <= 0 ) {
|
---|
4311 | JpGraphError::RaiseL(25064);
|
---|
4312 | //(" 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.");
|
---|
4313 | }
|
---|
4314 |
|
---|
4315 | $this->major_step=$aMajStep;
|
---|
4316 | $this->minor_step=$aMinStep;
|
---|
4317 | $this->is_set = true;
|
---|
4318 | }
|
---|
4319 |
|
---|
4320 | function SetMajTickPositions($aMajPos,$aLabels=NULL) {
|
---|
4321 | $this->SetTickPositions($aMajPos,NULL,$aLabels);
|
---|
4322 | }
|
---|
4323 |
|
---|
4324 | function SetTickPositions($aMajPos,$aMinPos=NULL,$aLabels=NULL) {
|
---|
4325 | if( !is_array($aMajPos) || ($aMinPos!==NULL && !is_array($aMinPos)) ) {
|
---|
4326 | JpGraphError::RaiseL(25065);//('Tick positions must be specifued as an array()');
|
---|
4327 | return;
|
---|
4328 | }
|
---|
4329 | $n=count($aMajPos);
|
---|
4330 | if( is_array($aLabels) && (count($aLabels) != $n) ) {
|
---|
4331 | JpGraphError::RaiseL(25066);//('When manually specifying tick positions and labels the number of labels must be the same as the number of specified ticks.');
|
---|
4332 | }
|
---|
4333 | $this->iManualTickPos = $aMajPos;
|
---|
4334 | $this->iManualMinTickPos = $aMinPos;
|
---|
4335 | $this->iManualTickLabels = $aLabels;
|
---|
4336 | }
|
---|
4337 |
|
---|
4338 | function HaveManualLabels() {
|
---|
4339 | return is_array($this->iManualTickLabels) ? count($this->iManualTickLabels) > 0 : false;
|
---|
4340 | }
|
---|
4341 |
|
---|
4342 | // Specify all the tick positions manually and possible also the exact labels
|
---|
4343 | function _doManualTickPos($aScale) {
|
---|
4344 | $n=count($this->iManualTickPos);
|
---|
4345 | $m= is_array($this->iManualMinTickPos) ? count($this->iManualMinTickPos) : 0;
|
---|
4346 | $doLbl= is_array($this->iManualTickLabels) ? count($this->iManualTickLabels) > 0 : false;
|
---|
4347 |
|
---|
4348 | $this->maj_ticks_pos = array();
|
---|
4349 | $this->maj_ticklabels_pos = array();
|
---|
4350 | $this->ticks_pos = array();
|
---|
4351 |
|
---|
4352 | // Now loop through the supplied positions and translate them to screen coordinates
|
---|
4353 | // and store them in the maj_label_positions
|
---|
4354 | $minScale = $aScale->scale[0];
|
---|
4355 | $maxScale = $aScale->scale[1];
|
---|
4356 | $j=0;
|
---|
4357 | for($i=0; $i < $n ; ++$i ) {
|
---|
4358 | // First make sure that the first tick is not lower than the lower scale value
|
---|
4359 | if( !isset($this->iManualTickPos[$i]) || $this->iManualTickPos[$i] < $minScale || $this->iManualTickPos[$i] > $maxScale) {
|
---|
4360 | continue;
|
---|
4361 | }
|
---|
4362 |
|
---|
4363 | $this->maj_ticks_pos[$j] = $aScale->Translate($this->iManualTickPos[$i]);
|
---|
4364 | $this->maj_ticklabels_pos[$j] = $this->maj_ticks_pos[$j];
|
---|
4365 |
|
---|
4366 | // Set the minor tick marks the same as major if not specified
|
---|
4367 | if( $m <= 0 ) {
|
---|
4368 | $this->ticks_pos[$j] = $this->maj_ticks_pos[$j];
|
---|
4369 | }
|
---|
4370 | if( $doLbl ) {
|
---|
4371 | $this->maj_ticks_label[$j] = $this->iManualTickLabels[$i];
|
---|
4372 | }
|
---|
4373 | else {
|
---|
4374 | $this->maj_ticks_label[$j]=$this->_doLabelFormat($this->iManualTickPos[$i],$i,$n);
|
---|
4375 | }
|
---|
4376 | ++$j;
|
---|
4377 | }
|
---|
4378 |
|
---|
4379 | // Some sanity check
|
---|
4380 | if( count($this->maj_ticks_pos) < 2 ) {
|
---|
4381 | JpGraphError::RaiseL(25067);//('Your manually specified scale and ticks is not correct. The scale seems to be too small to hold any of the specified tickl marks.');
|
---|
4382 | }
|
---|
4383 |
|
---|
4384 | // Setup the minor tick marks
|
---|
4385 | $j=0;
|
---|
4386 | for($i=0; $i < $m; ++$i ) {
|
---|
4387 | if( empty($this->iManualMinTickPos[$i]) || $this->iManualMinTickPos[$i] < $minScale || $this->iManualMinTickPos[$i] > $maxScale) {
|
---|
4388 | continue;
|
---|
4389 | }
|
---|
4390 | $this->ticks_pos[$j] = $aScale->Translate($this->iManualMinTickPos[$i]);
|
---|
4391 | ++$j;
|
---|
4392 | }
|
---|
4393 | }
|
---|
4394 |
|
---|
4395 | function _doAutoTickPos($aScale) {
|
---|
4396 | $maj_step_abs = $aScale->scale_factor*$this->major_step;
|
---|
4397 | $min_step_abs = $aScale->scale_factor*$this->minor_step;
|
---|
4398 |
|
---|
4399 | if( $min_step_abs==0 || $maj_step_abs==0 ) {
|
---|
4400 | JpGraphError::RaiseL(25068);//("A plot has an illegal scale. This could for example be that you are trying to use text autoscaling to draw a line plot with only one point or that the plot area is too small. It could also be that no input data value is numeric (perhaps only '-' or 'x')");
|
---|
4401 | }
|
---|
4402 | // We need to make this an int since comparing it below
|
---|
4403 | // with the result from round() can give wrong result, such that
|
---|
4404 | // (40 < 40) == TRUE !!!
|
---|
4405 | $limit = (int)$aScale->scale_abs[1];
|
---|
4406 |
|
---|
4407 | if( $aScale->textscale ) {
|
---|
4408 | // This can only be true for a X-scale (horizontal)
|
---|
4409 | // Define ticks for a text scale. This is slightly different from a
|
---|
4410 | // normal linear type of scale since the position might be adjusted
|
---|
4411 | // and the labels start at on
|
---|
4412 | $label = (float)$aScale->GetMinVal()+$this->text_label_start+$this->label_offset;
|
---|
4413 | $start_abs=$aScale->scale_factor*$this->text_label_start;
|
---|
4414 | $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1;
|
---|
4415 |
|
---|
4416 | $x = $aScale->scale_abs[0]+$start_abs+$this->xlabel_offset*$min_step_abs;
|
---|
4417 | for( $i=0; $label <= $aScale->GetMaxVal()+$this->label_offset; ++$i ) {
|
---|
4418 | // Apply format to label
|
---|
4419 | $this->maj_ticks_label[$i]=$this->_doLabelFormat($label,$i,$nbrmajticks);
|
---|
4420 | $label+=$this->major_step;
|
---|
4421 |
|
---|
4422 | // The x-position of the tick marks can be different from the labels.
|
---|
4423 | // Note that we record the tick position (not the label) so that the grid
|
---|
4424 | // happen upon tick marks and not labels.
|
---|
4425 | $xtick=$aScale->scale_abs[0]+$start_abs+$this->xtick_offset*$min_step_abs+$i*$maj_step_abs;
|
---|
4426 | $this->maj_ticks_pos[$i]=$xtick;
|
---|
4427 | $this->maj_ticklabels_pos[$i] = round($x);
|
---|
4428 | $x += $maj_step_abs;
|
---|
4429 | }
|
---|
4430 | }
|
---|
4431 | else {
|
---|
4432 | $label = $aScale->GetMinVal();
|
---|
4433 | $abs_pos = $aScale->scale_abs[0];
|
---|
4434 | $j=0; $i=0;
|
---|
4435 | $step = round($maj_step_abs/$min_step_abs);
|
---|
4436 | if( $aScale->type == "x" ) {
|
---|
4437 | // For a normal linear type of scale the major ticks will always be multiples
|
---|
4438 | // of the minor ticks. In order to avoid any rounding issues the major ticks are
|
---|
4439 | // defined as every "step" minor ticks and not calculated separately
|
---|
4440 | $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1;
|
---|
4441 | while( round($abs_pos) <= $limit ) {
|
---|
4442 | $this->ticks_pos[] = round($abs_pos);
|
---|
4443 | $this->ticks_label[] = $label;
|
---|
4444 | if( $step== 0 || $i % $step == 0 && $j < $nbrmajticks ) {
|
---|
4445 | $this->maj_ticks_pos[$j] = round($abs_pos);
|
---|
4446 | $this->maj_ticklabels_pos[$j] = round($abs_pos);
|
---|
4447 | $this->maj_ticks_label[$j]=$this->_doLabelFormat($label,$j,$nbrmajticks);
|
---|
4448 | ++$j;
|
---|
4449 | }
|
---|
4450 | ++$i;
|
---|
4451 | $abs_pos += $min_step_abs;
|
---|
4452 | $label+=$this->minor_step;
|
---|
4453 | }
|
---|
4454 | }
|
---|
4455 | elseif( $aScale->type == "y" ) {
|
---|
4456 | //@todo s=2:20,12 s=1:50,6 $this->major_step:$nbr
|
---|
4457 | // abs_point,limit s=1:270,80 s=2:540,160
|
---|
4458 | // $this->major_step = 50;
|
---|
4459 | $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal())/$this->major_step)+1;
|
---|
4460 | // $step = 5;
|
---|
4461 | while( round($abs_pos) >= $limit ) {
|
---|
4462 | $this->ticks_pos[$i] = round($abs_pos);
|
---|
4463 | $this->ticks_label[$i]=$label;
|
---|
4464 | if( $step== 0 || $i % $step == 0 && $j < $nbrmajticks) {
|
---|
4465 | $this->maj_ticks_pos[$j] = round($abs_pos);
|
---|
4466 | $this->maj_ticklabels_pos[$j] = round($abs_pos);
|
---|
4467 | $this->maj_ticks_label[$j]=$this->_doLabelFormat($label,$j,$nbrmajticks);
|
---|
4468 | ++$j;
|
---|
4469 | }
|
---|
4470 | ++$i;
|
---|
4471 | $abs_pos += $min_step_abs;
|
---|
4472 | $label += $this->minor_step;
|
---|
4473 | }
|
---|
4474 | }
|
---|
4475 | }
|
---|
4476 | }
|
---|
4477 |
|
---|
4478 | function AdjustForDST($aFlg=true) {
|
---|
4479 | $this->iAdjustForDST = $aFlg;
|
---|
4480 | }
|
---|
4481 |
|
---|
4482 |
|
---|
4483 | function _doLabelFormat($aVal,$aIdx,$aNbrTicks) {
|
---|
4484 |
|
---|
4485 | // If precision hasn't been specified set it to a sensible value
|
---|
4486 | if( $this->precision==-1 ) {
|
---|
4487 | $t = log10($this->minor_step);
|
---|
4488 | if( $t > 0 || $t === 0.0) {
|
---|
4489 | $precision = 0;
|
---|
4490 | }
|
---|
4491 | else {
|
---|
4492 | $precision = -floor($t);
|
---|
4493 | }
|
---|
4494 | }
|
---|
4495 | else {
|
---|
4496 | $precision = $this->precision;
|
---|
4497 | }
|
---|
4498 |
|
---|
4499 | if( $this->label_formfunc != '' ) {
|
---|
4500 | $f=$this->label_formfunc;
|
---|
4501 | if( $this->label_formatstr == '' ) {
|
---|
4502 | $l = call_user_func($f,$aVal);
|
---|
4503 | }
|
---|
4504 | else {
|
---|
4505 | $l = sprintf($this->label_formatstr, call_user_func($f,$aVal));
|
---|
4506 | }
|
---|
4507 | }
|
---|
4508 | elseif( $this->label_formatstr != '' || $this->label_dateformatstr != '' ) {
|
---|
4509 | if( $this->label_usedateformat ) {
|
---|
4510 | // Adjust the value to take daylight savings into account
|
---|
4511 | if (date("I",$aVal)==1 && $this->iAdjustForDST ) {
|
---|
4512 | // DST
|
---|
4513 | $aVal+=3600;
|
---|
4514 | }
|
---|
4515 |
|
---|
4516 | $l = date($this->label_formatstr,$aVal);
|
---|
4517 | if( $this->label_formatstr == 'W' ) {
|
---|
4518 | // If we use week formatting then add a single 'w' in front of the
|
---|
4519 | // week number to differentiate it from dates
|
---|
4520 | $l = 'w'.$l;
|
---|
4521 | }
|
---|
4522 | }
|
---|
4523 | else {
|
---|
4524 | |
---|