Subversion Repositories Sites.obs-saisons.fr

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 aurelien 1
<?php
2
/*=======================================================================
3
// File: 	JPGRAPH_UTILS.INC
4
// Description: Collection of non-essential "nice to have" utilities
5
// Created: 	2005-11-20
6
// Ver:		$Id: jpgraph_utils.inc.php 1089 2009-01-18 22:30:30Z ljp $
7
//
8
// Copyright (c) Aditus Consulting. All rights reserved.
9
//========================================================================
10
*/
11
 
12
//===================================================
13
// CLASS FuncGenerator
14
// Description: Utility class to help generate data for function plots.
15
// The class supports both parametric and regular functions.
16
//===================================================
17
class FuncGenerator {
18
    var $iFunc='',$iXFunc='',$iMin,$iMax,$iStepSize;
19
 
20
    function FuncGenerator($aFunc,$aXFunc='') {
21
	$this->iFunc = $aFunc;
22
	$this->iXFunc = $aXFunc;
23
    }
24
 
25
    function E($aXMin,$aXMax,$aSteps=50) {
26
	$this->iMin = $aXMin;
27
	$this->iMax = $aXMax;
28
	$this->iStepSize = ($aXMax-$aXMin)/$aSteps;
29
 
30
	if( $this->iXFunc != '' )
31
	    $t = 'for($i='.$aXMin.'; $i<='.$aXMax.'; $i += '.$this->iStepSize.') {$ya[]='.$this->iFunc.';$xa[]='.$this->iXFunc.';}';
32
	elseif( $this->iFunc != '' )
33
	    $t = 'for($x='.$aXMin.'; $x<='.$aXMax.'; $x += '.$this->iStepSize.') {$ya[]='.$this->iFunc.';$xa[]=$x;} $x='.$aXMax.';$ya[]='.$this->iFunc.';$xa[]=$x;';
34
	else
35
	    JpGraphError::RaiseL(24001);//('FuncGenerator : No function specified. ');
36
 
37
	@eval($t);
38
 
39
	// If there is an error in the function specifcation this is the only
40
	// way we can discover that.
41
	if( empty($xa) || empty($ya) )
42
	    JpGraphError::RaiseL(24002);//('FuncGenerator : Syntax error in function specification ');
43
 
44
	return array($xa,$ya);
45
    }
46
}
47
 
48
//=============================================================================
49
// CLASS SymChar
50
// Description: Code values for some commonly used characters that
51
//              normally isn't available directly on the keyboard, for example
52
//              mathematical and greek symbols.
53
//=============================================================================
54
class  SymChar {
55
    function Get($aSymb,$aCapital=FALSE) {
56
        static $iSymbols = array(
57
    /* Greek */
58
	array('alpha','03B1','0391'),
59
	array('beta','03B2','0392'),
60
	array('gamma','03B3','0393'),
61
	array('delta','03B4','0394'),
62
	array('epsilon','03B5','0395'),
63
	array('zeta','03B6','0396'),
64
	array('ny','03B7','0397'),
65
	array('eta','03B8','0398'),
66
	array('theta','03B8','0398'),
67
	array('iota','03B9','0399'),
68
	array('kappa','03BA','039A'),
69
	array('lambda','03BB','039B'),
70
	array('mu','03BC','039C'),
71
	array('nu','03BD','039D'),
72
	array('xi','03BE','039E'),
73
	array('omicron','03BF','039F'),
74
	array('pi','03C0','03A0'),
75
	array('rho','03C1','03A1'),
76
	array('sigma','03C3','03A3'),
77
	array('tau','03C4','03A4'),
78
	array('upsilon','03C5','03A5'),
79
	array('phi','03C6','03A6'),
80
	array('chi','03C7','03A7'),
81
	array('psi','03C8','03A8'),
82
	array('omega','03C9','03A9'),
83
    /* Money */
84
	array('euro','20AC'),
85
	array('yen','00A5'),
86
	array('pound','20A4'),
87
    /* Math */
88
	array('approx','2248'),
89
	array('neq','2260'),
90
	array('not','2310'),
91
	array('def','2261'),
92
	array('inf','221E'),
93
	array('sqrt','221A'),
94
	array('int','222B'),
95
    /* Misc */
96
	array('copy','00A9'),
97
	array('para','00A7'),
98
	array('tm','2122'),   /* Trademark symbol */
99
	array('rtm','00AE')   /* Registered trademark */
100
);
101
 
102
	$n = count($iSymbols);
103
	$i=0;
104
	$found = false;
105
	$aSymb = strtolower($aSymb);
106
	while( $i < $n && !$found ) {
107
	    $found = $aSymb === $iSymbols[$i++][0];
108
	}
109
	if( $found ) {
110
	    $ca = $iSymbols[--$i];
111
	    if( $aCapital && count($ca)==3 )
112
		$s = $ca[2];
113
	    else
114
		$s = $ca[1];
115
	    return sprintf('&#%04d;',hexdec($s));
116
	}
117
	else
118
	    return '';
119
    }
120
}
121
 
122
 
123
//=============================================================================
124
// CLASS DateScaleUtils
125
// Description: Help to create a manual date scale
126
//=============================================================================
127
DEFINE('DSUTILS_MONTH',1); // Major and minor ticks on a monthly basis
128
DEFINE('DSUTILS_MONTH1',1); // Major and minor ticks on a monthly basis
129
DEFINE('DSUTILS_MONTH2',2); // Major ticks on a bi-monthly basis
130
DEFINE('DSUTILS_MONTH3',3); // Major icks on a tri-monthly basis
131
DEFINE('DSUTILS_MONTH6',4); // Major on a six-monthly basis
132
DEFINE('DSUTILS_WEEK1',5); // Major ticks on a weekly basis
133
DEFINE('DSUTILS_WEEK2',6); // Major ticks on a bi-weekly basis
134
DEFINE('DSUTILS_WEEK4',7); // Major ticks on a quod-weekly basis
135
DEFINE('DSUTILS_DAY1',8); // Major ticks on a daily basis
136
DEFINE('DSUTILS_DAY2',9); // Major ticks on a bi-daily basis
137
DEFINE('DSUTILS_DAY4',10); // Major ticks on a qoud-daily basis
138
DEFINE('DSUTILS_YEAR1',11); // Major ticks on a yearly basis
139
DEFINE('DSUTILS_YEAR2',12); // Major ticks on a bi-yearly basis
140
DEFINE('DSUTILS_YEAR5',13); // Major ticks on a five-yearly basis
141
 
142
 
143
class DateScaleUtils {
144
    var $iMin=0, $iMax=0;
145
    var $starthour,$startmonth, $startday, $startyear;
146
    var $endmonth, $endyear, $endday;
147
    var $tickPositions=array(),$minTickPositions=array();
148
    var $iUseWeeks = true;
149
 
150
    function UseWeekFormat($aFlg) {
151
	$this->iUseWeeks = $aFlg;
152
    }
153
 
154
    function doYearly($aType,$aMinor=false) {
155
	$i=0; $j=0;
156
	$m = $this->startmonth;
157
	$y = $this->startyear;
158
 
159
	if( $this->startday == 1 ) {
160
	    $this->tickPositions[$i++] = mktime(0,0,0,$m,1,$y);
161
	}
162
	++$m;
163
 
164
	switch( $aType ) {
165
	    case DSUTILS_YEAR1:
166
		for($y=$this->startyear; $y <= $this->endyear; ++$y ) {
167
		    if( $aMinor ) {
168
			while( $m <= 12 ) {
169
			    if( !($y == $this->endyear && $m > $this->endmonth) ) {
170
				$this->minTickPositions[$j++] = mktime(0,0,0,$m,1,$y);
171
			    }
172
			    ++$m;
173
			}
174
			$m=1;
175
		    }
176
		    $this->tickPositions[$i++] = mktime(0,0,0,1,1,$y);
177
		}
178
		break;
179
	    case DSUTILS_YEAR2:
180
		$y=$this->startyear;
181
		while( $y <= $this->endyear ) {
182
		    $this->tickPositions[$i++] = mktime(0,0,0,1,1,$y);
183
		    for($k=0; $k < 1; ++$k ) {
184
			++$y;
185
			if( $aMinor ) {
186
			    $this->minTickPositions[$j++] = mktime(0,0,0,1,1,$y);
187
			}
188
		    }
189
		    ++$y;
190
		}
191
		break;
192
	    case DSUTILS_YEAR5:
193
		$y=$this->startyear;
194
		while( $y <= $this->endyear ) {
195
		    $this->tickPositions[$i++] = mktime(0,0,0,1,1,$y);
196
		    for($k=0; $k < 4; ++$k ) {
197
			++$y;
198
			if( $aMinor ) {
199
			    $this->minTickPositions[$j++] = mktime(0,0,0,1,1,$y);
200
			}
201
		    }
202
		    ++$y;
203
		}
204
		break;
205
	}
206
    }
207
 
208
    function doDaily($aType,$aMinor=false) {
209
	$m = $this->startmonth;
210
	$y = $this->startyear;
211
	$d = $this->startday;
212
	$h = $this->starthour;
213
	$i=0;$j=0;
214
 
215
	if( $h == 0 ) {
216
	    $this->tickPositions[$i++] = mktime(0,0,0,$m,$d,$y);
217
	}
218
	$t = mktime(0,0,0,$m,$d,$y);
219
	switch($aType) {
220
	    case DSUTILS_DAY1:
221
		while( $t <= self::$iMax ) {
222
		    $t = strtotime('+1 day',$t);
223
		    $this->tickPositions[$i++] = $t;
224
		    if( $aMinor ) {
225
			$this->minTickPositions[$j++] = strtotime('+12 hours',$t);
226
		    }
227
		}
228
		break;
229
	    case DSUTILS_DAY2:
230
		while( $t <= $this->iMax ) {
231
		    $t = strtotime('+1 day',$t);
232
		    if( $aMinor ) {
233
			$this->minTickPositions[$j++] = $t;
234
		    }
235
		    $t = strtotime('+1 day',$t);
236
		    $this->tickPositions[$i++] = $t;
237
		}
238
		break;
239
	    case DSUTILS_DAY4:
240
		while( $t <= $this->iMax ) {
241
		    for($k=0; $k < 3; ++$k ) {
242
			$t = strtotime('+1 day',$t);
243
			if( $aMinor ) {
244
			    $this->minTickPositions[$j++] = $t;
245
			}
246
		    }
247
		    $t = strtotime('+1 day',$t);
248
		    $this->tickPositions[$i++] = $t;
249
		}
250
		break;
251
	}
252
    }
253
 
254
    function doWeekly($aType,$aMinor=false) {
255
	$hpd = 3600*24;
256
	$hpw = 3600*24*7;
257
	// Find out week number of min date
258
	$thursday = $this->iMin + $hpd * (3 - (date('w', $this->iMin) + 6) % 7);
259
	$week = 1 + (date('z', $thursday) - (11 - date('w', mktime(0, 0, 0, 1, 1, date('Y', $thursday)))) % 7) / 7;
260
	$daynumber = date('w',$this->iMin);
261
	if( $daynumber == 0 ) $daynumber = 7;
262
	$m = $this->startmonth;
263
	$y = $this->startyear;
264
	$d = $this->startday;
265
	$i=0;$j=0;
266
	// The assumption is that the weeks start on Monday. If the first day
267
	// is later in the week then the first week tick has to be on the following
268
	// week.
269
	if( $daynumber == 1 ) {
270
	    $this->tickPositions[$i++] = mktime(0,0,0,$m,$d,$y);
271
	    $t = mktime(0,0,0,$m,$d,$y) + $hpw;
272
	}
273
	else {
274
	    $t = mktime(0,0,0,$m,$d,$y) + $hpd*(8-$daynumber);
275
	}
276
 
277
	switch($aType) {
278
	    case DSUTILS_WEEK1:
279
		$cnt=0;
280
		break;
281
	    case DSUTILS_WEEK2:
282
		$cnt=1;
283
		break;
284
	    case DSUTILS_WEEK4:
285
		$cnt=3;
286
		break;
287
	}
288
	while( $t <= $this->iMax ) {
289
	    $this->tickPositions[$i++] = $t;
290
	    for($k=0; $k < $cnt; ++$k ) {
291
		$t += $hpw;
292
		if( $aMinor ) {
293
		    $this->minTickPositions[$j++] = $t;
294
		}
295
	    }
296
	    $t += $hpw;
297
	}
298
    }
299
 
300
    function doMonthly($aType,$aMinor=false) {
301
	$monthcount=0;
302
	$m = $this->startmonth;
303
	$y = $this->startyear;
304
	$i=0; $j=0;
305
 
306
	// Skip the first month label if it is before the startdate
307
	if( $this->startday == 1 ) {
308
	    $this->tickPositions[$i++] = mktime(0,0,0,$m,1,$y);
309
	    $monthcount=1;
310
	}
311
	if( $aType == 1 ) {
312
	    if( $this->startday < 15 ) {
313
		$this->minTickPositions[$j++] = mktime(0,0,0,$m,15,$y);
314
	    }
315
	}
316
	++$m;
317
 
318
	// Loop through all the years included in the scale
319
	for($y=$this->startyear; $y <= $this->endyear; ++$y ) {
320
	    // Loop through all the months. There are three cases to consider:
321
	    // 1. We are in the first year and must start with the startmonth
322
	    // 2. We are in the end year and we must stop at last month of the scale
323
	    // 3. A year in between where we run through all the 12 months
324
	    $stopmonth = $y == $this->endyear ? $this->endmonth : 12;
325
	    while( $m <= $stopmonth ) {
326
		switch( $aType ) {
327
		    case DSUTILS_MONTH1:
328
			// Set minor tick at the middle of the month
329
			if( $aMinor ) {
330
			    if( $m <= $stopmonth ) {
331
				if( !($y==$this->endyear && $m==$stopmonth && $this->endday < 15) )
332
				$this->minTickPositions[$j++] = mktime(0,0,0,$m,15,$y);
333
			    }
334
			}
335
			// Major at month
336
			// Get timestamp of first hour of first day in each month
337
			$this->tickPositions[$i++] = mktime(0,0,0,$m,1,$y);
338
 
339
			break;
340
		    case DSUTILS_MONTH2:
341
			if( $aMinor ) {
342
			    // Set minor tick at start of each month
343
			    $this->minTickPositions[$j++] = mktime(0,0,0,$m,1,$y);
344
			}
345
 
346
			// Major at every second month
347
			// Get timestamp of first hour of first day in each month
348
			if( $monthcount % 2 == 0 ) {
349
			    $this->tickPositions[$i++] = mktime(0,0,0,$m,1,$y);
350
			}
351
			break;
352
		    case DSUTILS_MONTH3:
353
			if( $aMinor ) {
354
			    // Set minor tick at start of each month
355
			    $this->minTickPositions[$j++] = mktime(0,0,0,$m,1,$y);
356
			}
357
			    // Major at every third month
358
			// Get timestamp of first hour of first day in each month
359
			if( $monthcount % 3 == 0 ) {
360
			    $this->tickPositions[$i++] = mktime(0,0,0,$m,1,$y);
361
			}
362
			break;
363
		    case DSUTILS_MONTH6:
364
			if( $aMinor ) {
365
			    // Set minor tick at start of each month
366
			    $this->minTickPositions[$j++] = mktime(0,0,0,$m,1,$y);
367
			}
368
			// Major at every third month
369
			// Get timestamp of first hour of first day in each month
370
			if( $monthcount % 6 == 0 ) {
371
			    $this->tickPositions[$i++] = mktime(0,0,0,$m,1,$y);
372
			}
373
			break;
374
		}
375
		++$m;
376
		++$monthcount;
377
	    }
378
	    $m=1;
379
	}
380
 
381
	// For the case where all dates are within the same month
382
	// we want to make sure we have at least two ticks on the scale
383
	// since the scale want work properly otherwise
384
	if($this->startmonth == $this->endmonth && $this->startyear == $this->endyear && $aType==1 ) {
385
	    $this->tickPositions[$i++] = mktime(0 ,0 ,0, $this->startmonth + 1, 1, $this->startyear);
386
	}
387
 
388
	return array($this->tickPositions,$this->minTickPositions);
389
    }
390
 
391
    function GetTicks($aData,$aType=1,$aMinor=false,$aEndPoints=false) {
392
	$n = count($aData);
393
	return $this->GetTicksFromMinMax($aData[0],$aData[$n-1],$aType,$aMinor,$aEndPoints);
394
    }
395
 
396
    function GetAutoTicks($aMin,$aMax,$aMaxTicks=10,$aMinor=false) {
397
	$diff = $aMax - $aMin;
398
	$spd = 3600*24;
399
	$spw = $spd*7;
400
	$spm = $spd*30;
401
	$spy = $spd*352;
402
 
403
	if( $this->iUseWeeks )
404
	    $w = 'W';
405
	else
406
	    $w = 'd M';
407
 
408
	// Decision table for suitable scales
409
	// First value: Main decision point
410
	// Second value: Array of formatting depending on divisor for wanted max number of ticks. <divisor><formatting><format-string>,..
411
	$tt = array(
412
	    array($spw, array(1,DSUTILS_DAY1,'d M',2,DSUTILS_DAY2,'d M',-1,DSUTILS_DAY4,'d M')),
413
	    array($spm, array(1,DSUTILS_DAY1,'d M',2,DSUTILS_DAY2,'d M',4,DSUTILS_DAY4,'d M',
414
			      7,DSUTILS_WEEK1,$w,-1,DSUTILS_WEEK2,$w)),
415
	    array($spy, array(1,DSUTILS_DAY1,'d M',2,DSUTILS_DAY2,'d M',4,DSUTILS_DAY4,'d M',
416
			      7,DSUTILS_WEEK1,$w,14,DSUTILS_WEEK2,$w,
417
			      30,DSUTILS_MONTH1,'M',60,DSUTILS_MONTH2,'M',-1,DSUTILS_MONTH3,'M')),
418
	    array(-1, array(30,DSUTILS_MONTH1,'M-Y',60,DSUTILS_MONTH2,'M-Y',90,DSUTILS_MONTH3,'M-Y',
419
			    180,DSUTILS_MONTH6,'M-Y',352,DSUTILS_YEAR1,'Y',704,DSUTILS_YEAR2,'Y',-1,DSUTILS_YEAR5,'Y')));
420
 
421
	$ntt = count($tt);
422
	$nd = floor($diff/$spd);
423
	for($i=0; $i < $ntt; ++$i ) {
424
	    if( $diff <= $tt[$i][0] || $i==$ntt-1) {
425
		$t = $tt[$i][1];
426
		$n = count($t)/3;
427
		for( $j=0; $j < $n; ++$j ) {
428
		    if( $nd/$t[3*$j] <= $aMaxTicks || $j==$n-1) {
429
			$type = $t[3*$j+1];
430
			$fs = $t[3*$j+2];
431
			list($tickPositions,$minTickPositions) = $this->GetTicksFromMinMax($aMin,$aMax,$type,$aMinor);
432
			return array($fs,$tickPositions,$minTickPositions,$type);
433
		    }
434
		}
435
	    }
436
	}
437
    }
438
 
439
    function GetTicksFromMinMax($aMin,$aMax,$aType,$aMinor=false,$aEndPoints=false) {
440
	$this->starthour = date('G',$aMin);
441
	$this->startmonth = date('n',$aMin);
442
	$this->startday = date('j',$aMin);
443
	$this->startyear = date('Y',$aMin);
444
	$this->endmonth = date('n',$aMax);
445
	$this->endyear = date('Y',$aMax);
446
	$this->endday = date('j',$aMax);
447
	$this->iMin = $aMin;
448
	$this->iMax = $aMax;
449
 
450
	if( $aType <= DSUTILS_MONTH6 ) {
451
	    $this->doMonthly($aType,$aMinor);
452
	}
453
	elseif( $aType <= DSUTILS_WEEK4 ) {
454
	    $this->doWeekly($aType,$aMinor);
455
	}
456
	elseif( $aType <= DSUTILS_DAY4 ) {
457
	    $this->doDaily($aType,$aMinor);
458
	}
459
	elseif( $aType <= DSUTILS_YEAR5 ) {
460
	    $this->doYearly($aType,$aMinor);
461
	}
462
	else {
463
	    JpGraphError::RaiseL(24003);
464
	}
465
	// put a label at the very left data pos
466
	if( $aEndPoints ) {
467
	    $tickPositions[$i++] = $aData[0];
468
	}
469
 
470
	// put a label at the very right data pos
471
	if( $aEndPoints ) {
472
	    $tickPositions[$i] = $aData[$n-1];
473
	}
474
 
475
	return array($this->tickPositions,$this->minTickPositions);
476
    }
477
 
478
}
479
 
480
//=============================================================================
481
// Class ReadFileData
482
//=============================================================================
483
Class ReadFileData {
484
 
485
    //----------------------------------------------------------------------------
486
    // Desciption:
487
    // Read numeric data from a file.
488
    // Each value should be separated by either a new line or by a specified
489
    // separator character (default is ',').
490
    // Before returning the data each value is converted to a proper float
491
    // value. The routine is robust in the sense that non numeric data in the
492
    // file will be discarded.
493
    //
494
    // Returns:
495
    // The number of data values read on success, FALSE on failure
496
    //----------------------------------------------------------------------------
497
    function FromCSV($aFile,&$aData,$aSepChar=',',$aMaxLineLength=1024) {
498
	$rh = fopen($aFile,'r');
499
	if( $rh === false )
500
	    return false;
501
	$tmp = array();
502
	$lineofdata = fgetcsv($rh, 1000, ',');
503
	while ( $lineofdata !== FALSE) {
504
	    $tmp = array_merge($tmp,$lineofdata);
505
	    $lineofdata = fgetcsv($rh, $aMaxLineLength, $aSepChar);
506
	}
507
	fclose($rh);
508
 
509
	// Now make sure that all data is numeric. By default
510
	// all data is read as strings
511
	$n = count($tmp);
512
	$aData = array();
513
	$cnt=0;
514
	for($i=0; $i < $n; ++$i) {
515
	    if( $tmp[$i] !== "" ) {
516
		$aData[$cnt++] = floatval($tmp[$i]);
517
	    }
518
	}
519
	return $cnt;
520
    }
521
}
522
 
523
?>