/dev/trunk

To get this branch, use:
bzr branch http://darksoft.org/webbzr/dev/trunk

« back to all changes in this revision

Viewing changes to classes/draw.php

  • Committer: Suren A. Chilingaryan
  • Date: 2008-04-02 10:23:22 UTC
  • Revision ID: csa@dside.dyndns.org-20080402102322-okib92sicg2dx3o3
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
 
 
3
include($JPGRAPH_PATH . "/jpgraph.php");
 
4
include($JPGRAPH_PATH . "/jpgraph_line.php");
 
5
include($JPGRAPH_PATH . "/jpgraph_date.php");
 
6
 
 
7
 
 
8
class DRAW {
 
9
 var $cache;
 
10
 var $req;
 
11
 var $interval, $mask;
 
12
 
 
13
 var $tmpfile;
 
14
 var $ready;
 
15
 
 
16
 var $width, $height;
 
17
 var $graph;
 
18
 
 
19
 var $use_cache_timewindow;
 
20
 var $set_time_axes;
 
21
 
 
22
 var $aggregator;               // Aggregating algorithm
 
23
 var $interpolate_gaps;         // Do not indicate missing data, do linear interpolation instead
 
24
 var $allowed_gap;              // The allowed gaps between data, report if greater (if no interpolation)
 
25
 
 
26
 var $show_marks;               // Set marks on the graph if data gaps are detected
 
27
 var $show_gaps;                // Present information about gaps in the data on graph
 
28
 
 
29
 
 
30
 const MARKS_NEVER = 0;
 
31
 const MARKS_DEFAULT = 1;
 
32
 const MARKS_GAPS = 2;
 
33
 const MARKS_ALWAYS = 3;
 
34
 
 
35
 const SHOW_NONE = 0;
 
36
 const SHOW_EMPTY = 1;
 
37
 const SHOW_POINTS = 2;
 
38
 const SHOW_GAPS = 3;
 
39
 
 
40
 
 
41
 function __construct(DATARequest &$props = NULL, CACHE &$cache = NULL) {
 
42
    global $GRAPH_DEFAULT_HEIGHT, $GRAPH_DEFAULT_WIDTH;
 
43
    global $TMP_PATH;
 
44
 
 
45
    global $GRAPH_INTERPOLATE_DATA_GAPS;
 
46
    global $GRAPH_ACCURACY_MARKS_IF_GAPS;
 
47
    
 
48
    global $GRAPH_INDICATE_MISSING_DATA;
 
49
    global $GRAPH_INDICATE_DATA_DENSITY;
 
50
 
 
51
    if ($props) $this->req = &$props;
 
52
    else $this->req = new DATARequest();
 
53
 
 
54
    if ($cache) $this->cache = &$cache;
 
55
    else $this->cache = $this->req->CreateCache();
 
56
 
 
57
    $opts = &$this->req->GetOptions();
 
58
    $this->use_cache_timewindow = $opts->Get('use_cache_timewindow');
 
59
    if ($this->use_cache_timewindow) {
 
60
        $this->interval = $this->req->CreateInterval();
 
61
        $this->interval->ApplyCache($this->cache);
 
62
    } else {
 
63
        $iinfo = $this->req->GetIntervalInfo();
 
64
        $this->interval = $this->cache->CreateInterval($iinfo);
 
65
    }
 
66
 
 
67
    $this->set_time_axes = !$opts->Get('optimize_time_axes');
 
68
 
 
69
    if (isset($this->req->props['aggregation']))
 
70
        $this->aggregator = $this->req->props['aggregation'];
 
71
    else
 
72
        $this->aggregator = CACHE::TYPE_AUTO;
 
73
    
 
74
    
 
75
    if (isset($this->req->props['show_marks']))
 
76
        $this->show_marks = $this->req->props['show_marks'];
 
77
    else {
 
78
        if ($GRAPH_ACCURACY_MARKS_IF_GAPS)
 
79
            $this->show_marks = DRAW::MARKS_GAPS;
 
80
        else 
 
81
            $this->show_marks = DRAW::MARKS_DEFAULT;
 
82
    }
 
83
 
 
84
    if (isset($this->req->props['show_gaps']))
 
85
        $this->show_gaps = $this->req->props['show_gaps'];
 
86
    else {
 
87
        if ($GRAPH_INDICATE_DATA_DENSITY) {
 
88
            eval("\$this->show_gaps = DRAW::$GRAPH_INDICATE_DATA_DENSITY;");
 
89
        } else {
 
90
            $this->show_gaps = $GRAPH_INDICATE_DATA_DENSITY;
 
91
        }
 
92
    }
 
93
    if (isset($this->req->props['interpolate']))
 
94
        $this->interpolate_gaps = $this->req->props['interpolate'];
 
95
    else
 
96
        $this->interpolate_gaps = $opts->Get('graph_interpolate', $GRAPH_INTERPOLATE_DATA_GAPS);
 
97
        
 
98
    $this->allowed_gap = $opts->Get('maximal_allowed_gap', false);
 
99
    
 
100
    
 
101
    $minfo = $this->req->GetMaskInfo();
 
102
    $this->mask = $this->cache->CreateMask($minfo);
 
103
 
 
104
    
 
105
    $this->tmpfile = $this->GetTmpFile();
 
106
 
 
107
/*  DS, ToDo: We should restore some variables before we can reuse files 
 
108
    if (is_file($TMP_PATH . "/" .  $this->tmpfile)) $this->ready = true;
 
109
    else */{
 
110
        if (isset($this->req->props['frame_height'])) $this->height = $this->req->props['frame_height'];
 
111
        else $this->height = $GRAPH_DEFAULT_HEIGHT;
 
112
        if (isset($this->req->props['frame_width'])) $this->width = $this->req->props['frame_width'];
 
113
        else $this->width = $GRAPH_DEFAULT_WIDTH;
 
114
        
 
115
        $this->ready = false;
 
116
    }
 
117
 }
 
118
 
 
119
 function GetTmpFile() {
 
120
    global $ADEI_SESSION;
 
121
    global $TMP_PATH;
 
122
 
 
123
 
 
124
    $props = $this->req->props;
 
125
    unset($props['window']);
 
126
    unset($props['format']);
 
127
    unset($props['mask_mode']);
 
128
    unset($props['resample']);
 
129
    unset($props['filename']);
 
130
 
 
131
    $dir = "clients/" . $ADEI_SESSION . "/draw." . $this->req->props['db_server'] . "__" . $this->req->props['db_name'] . "__" . $this->req->props['db_group'] . "/" . md5(serialize($props)) . "/";
 
132
 
 
133
    if (!is_dir($TMP_PATH . "/" .  $dir)) {
 
134
        if (!@mkdir($TMP_PATH . "/" . $dir, 0755, true)) 
 
135
            throw new ADEIException(translate("DRAW class have not access to the temporary directory"));
 
136
    }
 
137
 
 
138
    return $dir . time() . "_" . $this->interval->window_start . "_" . $this->interval->window_size . ".png";
 
139
 }
 
140
 
 
141
 function GetAgregatingProperties(&$iv, $size) {
 
142
    global $GRAPH_MAX_POINTS_PER_GRAPH;
 
143
    global $GRAPH_MAX_APPROXIMATION_INTERVAL;
 
144
    global $GRAPH_AUTOAGGREGATION_MINMAX_THRESHOLD;
 
145
    
 
146
    $points = $this->width * $size;
 
147
    if ($points > $GRAPH_MAX_POINTS_PER_GRAPH) {
 
148
        $limit = (int)floor($this->width * $GRAPH_MAX_POINTS_PER_GRAPH / $points);
 
149
 
 
150
        $intivl = $this->width / $limit;
 
151
        if ($intivl > $GRAPH_MAX_APPROXIMATION_INTERVAL) {
 
152
            $limit = (int)ceil($this->width / $GRAPH_MAX_APPROXIMATION_INTERVAL);
 
153
        }
 
154
    } else $limit = $this->width;
 
155
 
 
156
    $precision = (int)ceil(2 * $this->width / $limit);
 
157
    
 
158
    $res = $this->cache->resolution->Get($iv, $limit /* amount is here */);
 
159
    
 
160
    if ($this->aggregator) $aggregator = $this->aggregator;
 
161
    else {
 
162
        if ($precision < $GRAPH_AUTOAGGREGATION_MINMAX_THRESHOLD) $aggregator = CACHE::TYPE_MINMAX;
 
163
        elseif (!$this->cache->resolution->GetWindowSize($res)) $aggregator = CACHE::TYPE_MINMAX;
 
164
        else  $aggregator = CACHE::TYPE_MEAN;
 
165
    }
 
166
 
 
167
    return array(
 
168
        "type" => $aggregator,
 
169
        "limit" => $limit,
 
170
        "amount" => $limit,
 
171
        "precision" => $precision,
 
172
        "resolution" => $res
 
173
    );
 
174
 }
 
175
 
 
176
 function Legend($x = false, $y = false, &$mask = NULL, INTERVAL &$ivl = NULL) {
 
177
    global $GRAPH_DELTA_SIZE;
 
178
 
 
179
    if ($ivl) $iv = $ivl;
 
180
    else $iv = $this->interval;
 
181
 
 
182
    if (!$mask) $mask = &$this->mask;
 
183
 
 
184
    $list = $this->cache->GetItemList($mask, 0);
 
185
    
 
186
    if ($x === false) {
 
187
        if (isset($this->req->props['x'])) $x = $this->req->props['x'];
 
188
        else throw new ADEIException(translate("The X coordinate is not specified"));
 
189
 
 
190
    }
 
191
    if ($y === false) {
 
192
        if (isset($this->req->props['y'])) $y = $this->req->props['y'];
 
193
        else throw new ADEIException(translate("The Y coordinate is not specified"));
 
194
    }
 
195
    
 
196
    if (isset($this->req->props['xmin'])) $xmin = $this->req->props['xmin'];
 
197
    else throw new ADEIException(translate("The XMin is not specified"));
 
198
    if (isset($this->req->props['xmax'])) $xmax = $this->req->props['xmax'];
 
199
    else throw new ADEIException(translate("The XMax is not specified"));
 
200
    if (isset($this->req->props['ymin'])) $ymin = $this->req->props['ymin'];
 
201
    else throw new ADEIException(translate("The YMin is not specified"));
 
202
    if (isset($this->req->props['ymax'])) $ymax = $this->req->props['ymax'];
 
203
    else throw new ADEIException(translate("The yMax is not specified"));
 
204
 
 
205
 
 
206
    $size = sizeof($this->mask->ids);
 
207
    $a = $this->GetAgregatingProperties($iv, $size);
 
208
    
 
209
    if ($a["limit"] > 0) {
 
210
        /*
 
211
            "4" is due to the fact what maximal approximation error is two
 
212
            intervals. See description in cache.php.
 
213
            FIXME: limit could be decreased due to the border points
 
214
        */
 
215
 
 
216
        if ($a['type'] == CACHE::TYPE_MINMAX)
 
217
            $delta_size = 4 * $this->width / $a["limit"]; 
 
218
        else
 
219
            $delta_size = 2 * $this->width / $a["limit"]; 
 
220
 
 
221
        if ($delta_size < $GRAPH_DELTA_SIZE)
 
222
            $delta_size = $GRAPH_DELTA_SIZE;
 
223
    } else {
 
224
        $delta_size = $GRAPH_DELTA_SIZE;
 
225
    }
 
226
    
 
227
//    echo "$delta_size ($GRAPH_DELTA_SIZE)\n";
 
228
//    exit;
 
229
    
 
230
//    echo date('c',$x) . "(" . date('c',$xmin) . " - " . date('c', $xmax) . ")\n";
 
231
 
 
232
    $iv->SetupInterval($xmin, $xmax);
 
233
    $iv->SetupWindow(INTERVAL::WINDOW_NEIGHBOURHOOD, $x,  (dsMathPreciseSubstract($xmax, $xmin) * $delta_size) / $this->width);
 
234
//    echo date('c',(int)$iv->window_start) . " - " . date('c',(int)$iv->GetWindowEnd())  . "\n";
 
235
 
 
236
/*    
 
237
    $iv->window_size = (dsMathPreciseSubstract($xmax, $xmin) * $delta_size) / $this->width;
 
238
    $iv->window_start = dsMathPreciseSubstract($x, $iv->window_size / 2);
 
239
    if ($iv->window_start < $xmin) {
 
240
        $iv->window_size -= dsMathPreciseSubstract($xmin, $iv->window_start);
 
241
        $iv->window_start = $xmin;
 
242
    }
 
243
*/
 
244
    
 
245
    $ywin = (($ymax - $ymin)  * $GRAPH_DELTA_SIZE) / $this->height;
 
246
    $min = $y - $ywin / 2;
 
247
    $max = $y + $ywin / 2;
 
248
    
 
249
    
 
250
    $flags = CACHE::TRUNCATE_INTERVALS;
 
251
    $iv->EnableFlexibility();
 
252
//    print_r($a);
 
253
//    exit;
 
254
    $points = $this->cache->GetIntervals($mask, $iv, 1, 0, $a["resolution"], $flags);
 
255
 
 
256
/*
 
257
    $f=fopen("/tmp/xxx6", "w");
 
258
    fprintf($f, "$x $y ($delta_size), [" . $this->width . "x" . $this->height . "]\n");
 
259
    fprintf($f, "$xmin - $xmax, $ymin:$ymax)\n");
 
260
    fprintf($f, "$resolution\n");
 
261
    fprintf($f, print_r($a,true));
 
262
    fprintf($f, print_r($mask, true));
 
263
    fprintf($f, print_r($iv, true));
 
264
    fprintf($f, print_r($list, true));
 
265
    fprintf($f, "ID's: " . $size . "\n");
 
266
*/
 
267
 
 
268
    $result = array(); $notfound = true;
 
269
    foreach($points as $t => $v) {
 
270
//      fwrite($f, $t . ": ");
 
271
//      fwrite($f, print_r($v, true));
 
272
        
 
273
//      echo date('c', $t) . "\n";
 
274
//      print_r($v); 
 
275
//      echo "!\n";
 
276
 
 
277
        for ($i=0;$i<$size;$i++) {
 
278
            if ((($v["max" .$i]<$min)||($v["min" .$i]>$max))==false) {
 
279
                array_push($result, array(
 
280
                    "id" => $i,
 
281
                    "name" => xml_escape($list[$i]['name'])
 
282
                ));
 
283
            }
 
284
        }
 
285
        $notfound = false;
 
286
        break;
 
287
    }
 
288
    
 
289
    if ($notfound) {
 
290
        $neighbors = $this->cache->GetNeighbors($mask, $x);
 
291
        if ((sizeof($neighbors['left']) > 0)&&(sizeof($neighbors['right']) > 0)) {
 
292
            $keys1 = array_keys($neighbors['left']); $x1=$keys1[0];
 
293
            $keys2 = array_keys($neighbors['right']);$x2=$keys2[0];
 
294
//          echo "X: $x ($xmin, $xmax)\n";
 
295
//          echo "Y: $y ($min, $max)\n";
 
296
 
 
297
//          echo "X: $x1, $x, $x2\n";
 
298
 
 
299
            $check1 = true;
 
300
            if ((!$this->interpolate_gaps)&&($this->allowed_gap)) {
 
301
                    /* We don't check expected gap, since otherwise this points
 
302
                    would be found before neighbors lookup */
 
303
                if ((dsMathPreciseSubstract($x, $x1)>$this->allowed_gap)||(dsMathPreciseSubstract($x2, $x)>$this->allowed_gap)) $check1 = false;
 
304
            }
 
305
 
 
306
            if (($check1)&&(dsMathPreciseCompare($x1, $xmin)>=0)&&(dsMathPreciseCompare($x2, $xmax)<=0)) {
 
307
                $coef = dsMathPreciseSubstract($x, $x1) / dsMathPreciseSubstract($x2, $x1);
 
308
//              echo $coef . "(" . $size . ")\n";
 
309
                for ($i=0;$i<$size;$i++) {
 
310
                    $y1 = $neighbors['left'][$x1][$i];
 
311
                    $y2 = $neighbors['right'][$x2][$i];
 
312
                    $y = $y1 + $coef*($y2 - $y1); //DS.Precision
 
313
                
 
314
//                  print "Y: $y1 - $y - $y2\n";
 
315
                    if (($y>$min)&&($y<$max)) {
 
316
                        array_push($result, array(
 
317
                            "id" => $i,
 
318
                            "name" => xml_escape($list[$i]['name'])
 
319
                        ));
 
320
                    }
 
321
                }
 
322
            }
 
323
        }
 
324
    }
 
325
    
 
326
/*    
 
327
//    fprintf($f, print_r($ivl, true));
 
328
    fprintf($f, print_r($result, true));
 
329
    fclose($f);
 
330
*/
 
331
    
 
332
    return array("legend" => $result);
 
333
 }
 
334
 
 
335
 function Create(&$mask = NULL, INTERVAL &$iv = NULL) {
 
336
    global $GRAPH_MARGINS;
 
337
    global $GRAPH_MAX_CACHE_GAP;
 
338
    global $GRAPH_COLORS;
 
339
    global $GRAPH_LINE_WEIGHT;
 
340
    global $GRAPH_ACCURACY_MARKS_OUTSET;
 
341
    global $GRAPH_ACCURACY_MARKS_MULTIOUTSET;
 
342
    global $GRAPH_ACCURACY_MARKS_COLOR;
 
343
    global $GRAPH_ACCURACY_MARKS_TYPE;
 
344
    global $GRAPH_ACCURACY_MARKS_SIZE;
 
345
    global $GRAPH_SUBSECOND_THRESHOLD;
 
346
    
 
347
    global $GRAPH_DENSITY_PLOT_VALID_SIZE;
 
348
    global $GRAPH_DENSITY_PLOT_VALID_COLOR;
 
349
    global $GRAPH_DENSITY_PLOT_INVALID_SIZE;
 
350
    global $GRAPH_DENSITY_PLOT_INVALID_COLOR;
 
351
    global $GRAPH_DENSITY_POINTS_TYPE;
 
352
    global $GRAPH_DENSITY_POINTS_SIZE;
 
353
    global $GRAPH_DENSITY_POINTS_COLOR;
 
354
    global $GRAPH_DENSITY_POINTS_OUTLINE;
 
355
    
 
356
    
 
357
 
 
358
    if ($this->ready) return;
 
359
    if (!$iv) $iv = &$this->interval;
 
360
    if (!$mask) $mask = &$this->mask;
 
361
 
 
362
    $size = sizeof($mask->ids);
 
363
    $a = $this->GetAgregatingProperties($iv, $size);
 
364
    $precision = $a['precision'];
 
365
/*    
 
366
    if ($a['limit']) $precision = (int)ceil(2 * $this->width / $a["limit"]);
 
367
    else $precision = 0;
 
368
*/
 
369
//    print_r($iv);
 
370
    $flags = ($this->interpolate_gaps?0:CACHE::REPORT_EMPTY)|(($this->show_gaps==DRAW::SHOW_GAPS)?CACHE::MISSING_INFO:0);
 
371
    $points = $this->cache->GetPoints($mask, $iv, $a['type'], $a['limit'], $a['amount'], $a['resolution'], $flags);
 
372
    if ($this->allowed_gap !== false) $points->SetOption("allowed_gap", $this->allowed_gap);
 
373
 
 
374
/*    
 
375
    if ($size > 1) {
 
376
        if ($size > 10) $points = 100;
 
377
        else if ($size > 5) $points = 20;
 
378
        else if ($size > 3) {
 
379
            $points = $this->width / $size;
 
380
        }
 
381
    
 
382
//      $points = $this->cache->GetPoints($mask, $iv, CACHE::TYPE_MINMAX);
 
383
        $points = $this->cache->GetPoints($mask, $iv, CACHE::TYPE_MINMAX, $points);
 
384
    } else {
 
385
        $points = $this->cache->GetPoints($mask, $iv, CACHE::TYPE_MINMAX, $this->width);
 
386
    }
 
387
*/
 
388
    
 
389
    $amount = 0;
 
390
    $time = array();
 
391
    $values = array();
 
392
    
 
393
    $missing = true;            // last point was missing
 
394
    $amount_on_missing = false;
 
395
    $time_on_addon = false;
 
396
    
 
397
    for ($i=0;$i<$size;$i++)
 
398
        $values[$i] = array();
 
399
 
 
400
    if (($iv->y_min)||($iv->y_max)) {
 
401
        $min = $iv->y_min;
 
402
        $max = $iv->y_max;
 
403
        
 
404
        for ($i=0;$i<$size;$i++) {
 
405
            $at_max[$i] = false;
 
406
            $at_min[$i] = false;
 
407
        }
 
408
    } else {
 
409
        $min = 0;
 
410
        $max = 0;
 
411
 
 
412
        if ($this->show_gaps) {
 
413
            $realmin = 1E+200;
 
414
            $realmax = -1E+200;
 
415
        }
 
416
    }
 
417
    
 
418
    if ($this->show_gaps) {
 
419
        $mvalue = array();
 
420
    }
 
421
    
 
422
    
 
423
 
 
424
    foreach($points as $t => $v) {
 
425
        if ($v) {
 
426
            if ($this->show_gaps) {
 
427
                $gapinfo = $points->missing_data();
 
428
                if ($gapinfo) array_push($mvalue, 1);
 
429
                else array_push($mvalue, 0);
 
430
            }
 
431
 
 
432
            $amount++;
 
433
 
 
434
            if ($missing) {
 
435
/*              if ($time_on_addon) {
 
436
                    if ($this->show_gaps) {
 
437
                        array_push($mvalue, 2);
 
438
                    }
 
439
 
 
440
                    array_push($time, $time_on_addon);
 
441
                    for ($i=0;$i<$size;$i++) {
 
442
                        array_push($values[$i], false);
 
443
                    }             
 
444
                        
 
445
                    $time_on_addon = false;  
 
446
                }*/
 
447
                    
 
448
                $amount_on_missing = $amount;
 
449
                $missing = false;
 
450
            }
 
451
 
 
452
 
 
453
            array_push($time, $t);
 
454
            if (($min)||($max)) {
 
455
                foreach ($v as $key => $value) {
 
456
                    if ($at_max[$key]) {
 
457
                        if ($value > $max) {
 
458
                            $value = "";
 
459
                        } else {
 
460
                            $at_max[$key] = false;
 
461
                            if ($value < $min) {
 
462
                                $value = $min;
 
463
                                $at_min[$key] = true;
 
464
                            }
 
465
                        }
 
466
                    } elseif ($at_min[$key]) {
 
467
                        if ($value < $min) {
 
468
                            $value = "";
 
469
                        } else {
 
470
                            $at_min[$key] = false;
 
471
                            if ($value > $max) {
 
472
                                $value = $max;
 
473
                                $at_max[$key] = true;
 
474
                            }
 
475
                        }
 
476
                    } else {
 
477
                        if ($value > $max) {
 
478
                            $value = $max;
 
479
                            $at_max[$key] = true;
 
480
                        } elseif ($value < $min) {
 
481
                            $value = $min;
 
482
                            $at_min[$key] = true;
 
483
                        }
 
484
                    }
 
485
                    array_push($values[$key], $value);
 
486
                }
 
487
            } else {
 
488
                if ($this->show_gaps) {
 
489
                    foreach ($v as $key => $value) {
 
490
                        if ($value < $realmin) $realmin = $value;
 
491
                        if ($value > $realmax) $realmax = $value;
 
492
                        array_push($values[$key], $value);
 
493
                    }
 
494
                } else {
 
495
                    foreach ($v as $key => $value) {
 
496
                        array_push($values[$key], $value);
 
497
                    }
 
498
                }
 
499
            }
 
500
        } else {
 
501
            if (!$missing) {
 
502
                if ($amount === $amount_on_missing) {
 
503
                    if ($this->show_gaps) {
 
504
                            /* Yes, this point is set only to prolong last single (standalone) point to interval,
 
505
                            so it would be visualized by jpgraph. But in reality it is not a point */
 
506
                        array_push($mvalue, 2);
 
507
                    }
 
508
 
 
509
                    $pos = sizeof($values[0]) - 1;
 
510
                    array_push($time, $time[$pos]);
 
511
                    for ($i=0;$i<$size;$i++) {
 
512
                        array_push($values[$i], $values[$i][$pos]);
 
513
                    }
 
514
                        
 
515
//                  $time_on_addon = $t;
 
516
                    $amount_on_missing = false;
 
517
                }
 
518
                
 
519
                if ($this->show_gaps) {
 
520
                    array_push($mvalue, 2);
 
521
                }
 
522
 
 
523
//              $time_on_addon = false;
 
524
 
 
525
                array_push($time, $t);
 
526
                for ($i=0;$i<$size;$i++) {
 
527
                    array_push($values[$i], false);
 
528
                }
 
529
 
 
530
 
 
531
                $missing = true;
 
532
            }
 
533
        }
 
534
    }
 
535
    
 
536
    if ((!$missing)&&($amount === $amount_on_missing)) {
 
537
        if ($this->show_gaps) {
 
538
            array_push($mvalue, 2);
 
539
        }
 
540
 
 
541
        $pos = sizeof($values[0]) - 1;
 
542
        array_push($time, $time[$pos]);//$t);
 
543
        for ($i=0;$i<$size;$i++) {
 
544
            array_push($values[$i], $values[$i][$pos]);
 
545
        }
 
546
    }
 
547
    
 
548
//    echo "Points detected: $amount(" . sizeof($time) . ")\n";
 
549
    
 
550
    if (!$amount)
 
551
        throw new ADEIException(translate("No data available"));
 
552
 
 
553
 
 
554
    if ($amount != sizeof($time)) {
 
555
        $have_gaps = true;
 
556
    } else {
 
557
        $have_gaps = $points->missing_points();
 
558
    }
 
559
 
 
560
 
 
561
    if ($this->show_gaps == DRAW::SHOW_GAPS) $show_gaps = DRAW::SHOW_GAPS;
 
562
    else if (($this->show_gaps == DRAW::SHOW_POINTS)||(($have_gaps)&&($this->show_gaps == DRAW::SHOW_EMPTY))) $show_gaps = DRAW::SHOW_POINTS;
 
563
    else $show_gaps = 0;
 
564
 
 
565
    if ($show_gaps) {
 
566
        if ((!$min)&&(!$max)) {
 
567
            if ($realmin == $realmax) {
 
568
                if ($realmin > 0) {
 
569
                    $px = $realmax / $this->height;
 
570
                    $min = 0;
 
571
                    $max = 2*$realmax;
 
572
                } elseif ($realmin < 0) {
 
573
                    $px = (-$realmax) / $this->height;
 
574
                    $min = 2*$realmin;
 
575
                    $max  = 0;
 
576
                } else {
 
577
                    $px = 1 / $this->height;
 
578
                    $max = 1;
 
579
                    $min = -1;
 
580
                }
 
581
            } else {
 
582
                $px = ($realmax - $realmin) / $this->height;
 
583
                $min = $realmin - 4 * $px;
 
584
                $max = $realmax + 4 * $px;
 
585
            }
 
586
        } else {
 
587
            $px = ($max - $min) / $this->height;
 
588
        }
 
589
 
 
590
        $realmax = $max + 2*$px;
 
591
        
 
592
//      echo "$min ($realmin)  , $max ($realmax) \n";
 
593
    }
 
594
 
 
595
 
 
596
//    print_r($time);
 
597
 
 
598
    $from = $time[0];
 
599
    $to = $time[sizeof($time)-1];
 
600
    $length = dsMathPreciseSubstract($to, $from);
 
601
    
 
602
        // Calculating real accuracy, but only if single plot, otherwise not important    
 
603
//    if ($size == 1) {
 
604
        $precision = (int)ceil(2 * $this->width / $amount);
 
605
//    }
 
606
 
 
607
    if ($GRAPH_MAX_CACHE_GAP) {
 
608
        if ((($from - $iv->window_start) < $GRAPH_MAX_CACHE_GAP)||
 
609
            (($to - $iv->window_start - $iv->window_size) < $GRAPH_MAX_CACHE_GAP)) {
 
610
            $range1 = date("c", ceil($iv->window_start)) . " and " . date("c", floor($iv->window_start + $iv->window_size));
 
611
            $range2 = date("c", ceil($from)) . " and " . date("c", floor($to));
 
612
            throw new ADEIException(translate("The data is missing in CACHE: Needed: $range1, Available: $range2"));
 
613
        }
 
614
    }
 
615
 
 
616
 
 
617
 
 
618
    $this->graph = new Graph($this->width, $this->height, "auto");
 
619
    $this->graph->img->SetMargin($GRAPH_MARGINS['left'],$GRAPH_MARGINS['top'],$GRAPH_MARGINS['right'],$GRAPH_MARGINS['bottom']);
 
620
 
 
621
 
 
622
//    $this->graph->SetTickDensity(TICKD_SPARSE, TICKD_VERYSPARSE);
 
623
//    $this->graph->title->Set("Example on Date scale");
 
624
//    $this->graph->xaxis->scale->SetTimeAlign(MINADJ_15);
 
625
//    $this->graph->xscale->SetGrace(10)
 
626
 
 
627
    if ($length > $GRAPH_SUBSECOND_THRESHOLD) {
 
628
        if (($this->set_time_axes)||($from == $to)) {
 
629
            $from = $iv->window_start;
 
630
            $to = dsMathPreciseAdd($iv->window_start, $iv->window_size);
 
631
            
 
632
            if (($min)||($max)) $this->graph->SetScale("datlin", $min, $max, $from, $to);
 
633
            else $this->graph->SetScale("datlin", true, true, $from, $to);
 
634
 
 
635
            $length = $iv->window_size;
 
636
        } else {
 
637
            if (($min)||($max)) $this->graph->SetScale("datlin", $min, $max);
 
638
            else $this->graph->SetScale("datlin");
 
639
        }
 
640
 
 
641
        $this->scale_start = 0;
 
642
        $this->scale_coef = 1;
 
643
    } else {
 
644
        if (($this->set_time_axes)||($from == $to)) {
 
645
            $from = $iv->window_start;
 
646
            $to = dsMathPreciseAdd($iv->window_start, $iv->window_size);
 
647
 
 
648
            $length = $iv->window_size;
 
649
 
 
650
            if ($length > $GRAPH_SUBSECOND_THRESHOLD) {
 
651
                if (($min)||($max)) $this->graph->SetScale("datlin", $min, $max, $from, $to);
 
652
                else $this->graph->SetScale("datlin", true, true, $from, $to);
 
653
            
 
654
                $this->scale_start = 0;
 
655
                $this->scale_coef = 1;
 
656
            }
 
657
        }
 
658
    }
 
659
 
 
660
 
 
661
    $afrom = getdate($from);
 
662
    $ato = getdate($to);
 
663
 
 
664
 
 
665
 
 
666
    if ($length > 315360000) { // 10 years 
 
667
        $this->graph->xaxis->scale->SetDateFormat('Y');
 
668
        $this->graph->xaxis->SetTextLabelInterval(1);
 
669
        $date_title = "";
 
670
    } elseif ($length > 31104000) { // 1 year
 
671
        $this->graph->xaxis->scale->SetDateFormat('M');
 
672
        $this->graph->xaxis->SetTextLabelInterval(2);
 
673
        
 
674
        if ($afrom['year'] == $ato['year']) $date_title = $afrom['year'];
 
675
        else $date_title = $afrom['year'] . " - " . $ato['year'];
 
676
    } elseif ($length > 1036800) { // 12 days
 
677
        $this->graph->xaxis->scale->SetDateFormat('M d');
 
678
        $this->graph->xaxis->SetTextLabelInterval(3);
 
679
        
 
680
        if ($afrom['year'] == $ato['year']) {
 
681
            if ($afrom['mon'] == $ato['mon']) {
 
682
                $date_title = $afrom['month'] . ", " . $afrom['year'];
 
683
            } else {
 
684
                $date_title = $afrom['year'];
 
685
            }
 
686
        } else {
 
687
            $date_title = $afrom['year'] . " - " . $ato['year'];
 
688
        }
 
689
    } elseif ($length > 86400) { // 1 day
 
690
        $this->graph->xaxis->scale->SetDateFormat('M d, H:i');
 
691
        $this->graph->xaxis->SetTextLabelInterval(4);
 
692
 
 
693
        if ($afrom['year'] == $ato['year']) {
 
694
            if ($afrom['mon'] == $ato['mon']) {
 
695
                $date_title = $afrom['month'] . ", " . $afrom['year'];
 
696
            } else {
 
697
                $date_title = $afrom['year'];
 
698
            }
 
699
        } else {
 
700
            $date_title = $afrom['year'] . " - " . $ato['year'];
 
701
        }
 
702
    } elseif ($length > 14400) { // 4 hours
 
703
        $this->graph->xaxis->SetTextLabelInterval(2);
 
704
        $this->graph->xaxis->scale->SetDateFormat('H:i');
 
705
 
 
706
        if ($afrom['year'] == $ato['year']) {
 
707
            if ($afrom['mon'] == $ato['mon']) {
 
708
                if ($afrom['mday'] == $ato['mday']) {
 
709
                    $date_title = $afrom['month'] . " " . $afrom['mday'] . ", " . $afrom['year'];
 
710
                } else {
 
711
                    $date_title = $afrom['month'] . " " . $afrom['mday'] . " - " . $ato['mday'] . ", " . $afrom['year'];
 
712
                }
 
713
            } else {
 
714
                $date_title = date("M", $from) . " " . $afrom['mday'] . " - " . date("M", $to) . " " . $ato['mday'] . ", " . $afrom['year'];
 
715
            }
 
716
        } else {
 
717
            $date_title = date("M j, Y", $from) . " - " . date("M j, Y", $to);
 
718
        }
 
719
    } else if ($length > $GRAPH_SUBSECOND_THRESHOLD) {
 
720
        if ($length > 10) $this->graph->xaxis->SetTextLabelInterval(4);
 
721
        else $this->graph->xaxis->SetTextLabelInterval(4);
 
722
        $this->graph->xaxis->scale->SetDateFormat('H:i:s');
 
723
 
 
724
        if ($afrom['year'] == $ato['year']) {
 
725
            if ($afrom['mon'] == $ato['mon']) {
 
726
                if ($afrom['mday'] == $ato['mday']) {
 
727
                    $date_title = $afrom['month'] . " " . $afrom['mday'] . ", " . $afrom['year'];
 
728
                } else {
 
729
                    $date_title = $afrom['month'] . " " . $afrom['mday'] . " - " . $ato['mday'] . ", " . $afrom['year'];
 
730
                }
 
731
            } else {
 
732
                $date_title = date("M", $from) . " " . $afrom['mday'] . " - " . date("M", $to) . " " . $ato['mday'] . ", " . $afrom['year'];
 
733
            }
 
734
        } else {
 
735
            $date_title = date("M j, Y", $from) . " - " . date("M j, Y", $to);
 
736
        }
 
737
    } else {
 
738
        $ifrom = floor($from);
 
739
        if (is_float($from)) $rfrom = substr(printf("%.9F", $from - $ifrom),2);
 
740
        else {
 
741
            $pos = strpos($from, ".");
 
742
            if ($pos === false) $rfrom = 0;
 
743
            else $rfrom = substr($from, $pos + 1);
 
744
        }
 
745
 
 
746
        $date_title = date("M j, Y H:i:s", $ifrom);
 
747
        if ($rfrom) {
 
748
            $date_title .= "." . $rfrom;
 
749
            $rfrom = "0.$rfrom";
 
750
        }
 
751
        
 
752
        if ($length > $this->width/1000)  {
 
753
            $coef = 1000;
 
754
            $suffix = "ms";
 
755
        }
 
756
        elseif ($length > $this->width/1000000)  {
 
757
            $coef = 1000000;
 
758
            $suffix = "us";
 
759
        } else {
 
760
            $coef = 1000000000;
 
761
            $suffix = "ns";
 
762
        }
 
763
 
 
764
        $reallength = (int)floor($length*$coef);
 
765
        $rem = ($reallength + 10) % 1000;
 
766
        if ($rem<20) $ilength = $reallength - ($rem - 10);
 
767
        else $ilength = $reallength;
 
768
        
 
769
//      echo $reallength . " - " . $length . "\n";
 
770
        
 
771
        $date_title .= " + " . $ilength . $suffix;
 
772
 
 
773
//      echo $coef . " - " . $ilength .  "(" . $length . ")\n";
 
774
        $first_num = substr($ilength, 0, 1);
 
775
        $second_num = substr($ilength, 1, 1);
 
776
        if ($second_num>4) {
 
777
            if ((++$first_num)==10)
 
778
                $istep = "1" . str_repeat("0", strlen($ilength) - 1);
 
779
            else 
 
780
                $istep = $first_num . str_repeat("0", strlen($ilength) - 2);
 
781
        } else $istep = $first_num . str_repeat("0", strlen($ilength) - 2);
 
782
 
 
783
        if (($min)||($max)) $this->graph->SetScale("linlin", $min, $max, 0, $reallength); // + 1);
 
784
        else $this->graph->SetScale("linlin", true, true, 0, $reallength);// + 1);
 
785
        $this->graph->xscale->ticks->Set($istep, $istep/4);
 
786
        
 
787
        $ticks = floor(($ilength+1) / $istep);
 
788
 
 
789
        if ($this->width < 350) {
 
790
            if ($this->width < 70) $lpt = $ticks;
 
791
            else $lpt = ceil ($ticks / ($this->width / 70));
 
792
        } else $lpt = round($ticks / 5);
 
793
        
 
794
        $this->graph->xaxis->SetTextLabelInterval($lpt);
 
795
        
 
796
        foreach ($time as &$t) {
 
797
            strstr($t, ".");
 
798
 
 
799
            $it = (int)floor($t);
 
800
            $pos = strpos($t, ".");
 
801
            if ($pos === false) $rt = 0;
 
802
            else $rt = "0." . substr($t, $pos + 1);
 
803
            
 
804
//          echo $coef . ": " . $t;
 
805
            $t = ($it - $ifrom)*$coef + floor(($rt - $rfrom)*$coef);
 
806
//          echo " - " . $t . "\n";
 
807
        }
 
808
        
 
809
        $this->scale_start = $from;
 
810
        $this->scale_coef = $coef;
 
811
 
 
812
//      $this->graph->xaxis->SetTextLabelInterval(1);
 
813
    }
 
814
 
 
815
    $title = $this->req->props['db_name'];
 
816
/*  Full location information. Too long
 
817
    $title = $this->req->props['db_server'] . ":" . $this->req->props['db_name'] . ":" . $this->req->props['db_group'];
 
818
*/      
 
819
/*    Precision information. Confusing 
 
820
*/
 
821
    $operation_info = $points->GetOperationInfo();
 
822
    
 
823
    if (isset($operation_info["resolution"])) $title .= ", res: " . $operation_info["resolution"];
 
824
    if (isset($operation_info["aggregation"])) {
 
825
        switch ($operation_info["aggregation"]) {
 
826
            case CACHE::TYPE_MINMAX:
 
827
                $title .= ", MMAX";
 
828
            break;
 
829
            case CACHE::TYPE_MEAN:
 
830
                $title .= ", MEAN";
 
831
            break;
 
832
        }
 
833
    }
 
834
    if ($precision) $title .= ", acc. " . $precision . "px";
 
835
    if ($date_title) $title = "$date_title ($title)";
 
836
    
 
837
    $this->graph->xaxis->SetFont(FF_ARIAL, FS_NORMAL, 8);
 
838
//    $this->graph->xaxis->SetLabelAngle(0);
 
839
 
 
840
    $this->graph->title->Set($title);
 
841
    $this->graph->xaxis->SetPos("min");
 
842
 
 
843
 
 
844
    switch ($this->show_marks) {
 
845
        case DRAW::MARKS_ALWAYS:
 
846
            $marks = true;
 
847
        break;
 
848
        case DRAW::MARKS_GAPS:
 
849
            if ($have_gaps) {
 
850
                $marks = true;
 
851
                break;
 
852
            }
 
853
        case DRAW::MARKS_DEFAULT:
 
854
            if ($size > 1) {
 
855
                if (($GRAPH_ACCURACY_MARKS_MULTIOUTSET)&&($precision > $GRAPH_ACCURACY_MARKS_MULTIOUTSET)) {
 
856
                    $marks = true;
 
857
                    break;
 
858
                }
 
859
            } else {
 
860
                if (($GRAPH_ACCURACY_MARKS_OUTSET)&&($precision > $GRAPH_ACCURACY_MARKS_OUTSET)) {
 
861
                    $marks = true;
 
862
                    break;
 
863
                }
 
864
            }
 
865
        case DRAW::MARKS_NEVER:
 
866
            $marks = false;
 
867
    }
 
868
        
 
869
 
 
870
    if ($marks) {
 
871
        if ($GRAPH_ACCURACY_MARKS_COLOR) $marks = $GRAPH_ACCURACY_MARKS_COLOR;
 
872
        else $marks = "black";
 
873
 
 
874
        if ($GRAPH_ACCURACY_MARKS_TYPE) {
 
875
            eval("\$mtype=$GRAPH_ACCURACY_MARKS_TYPE;");
 
876
        } else {
 
877
            $mtype = MARK_FILLEDCIRCLE;
 
878
        }
 
879
    }
 
880
 
 
881
    $no_data = true;
 
882
    for ($i = 0; $i < $size; $i++) {
 
883
/*
 
884
        $f = fopen("/tmp/xxx.7", "a+");
 
885
        fwrite($f, print_r($iv, true) . "\n");
 
886
        fwrite($f, $i . " of " . $size . "\n");
 
887
        fwrite($f, date("r", ceil($iv->window_start)) . " - " . date("r", floor($iv->window_start + $iv->window_size)) . "\n");
 
888
        fwrite($f, print_r($time, true));
 
889
        fwrite($f, print_r($values[$i], true));
 
890
        fclose($f);
 
891
*/
 
892
        if (sizeof($time) > 0) {
 
893
            $plot = new LinePlot($values[$i], $time);
 
894
            if (sizeof($GRAPH_COLORS)) {
 
895
                $color = $GRAPH_COLORS[$i%sizeof($GRAPH_COLORS)];
 
896
                $plot->SetColor($color);
 
897
                if ($GRAPH_LINE_WEIGHT) {
 
898
                    $plot->SetWeight($GRAPH_LINE_WEIGHT);
 
899
                }
 
900
            }
 
901
            
 
902
            
 
903
            if ($marks) {
 
904
                $plot->mark->SetType($mtype);
 
905
                if ($GRAPH_ACCURACY_MARKS_SIZE) $plot->mark->SetSize($GRAPH_ACCURACY_MARKS_SIZE);
 
906
                $plot->mark->SetFillColor(($color&&($size>1))?$color:$marks);
 
907
            }
 
908
            
 
909
            $this->graph->Add($plot);
 
910
            $no_data = false;
 
911
        }
 
912
    }
 
913
    
 
914
    if ($no_data) {
 
915
        $range = date("c", ceil($iv->window_start)) . " and " . date("c", floor($iv->window_start + $iv->window_size));
 
916
        throw new ADEIException(translate("No data between $range"));
 
917
    }
 
918
 
 
919
    if ($show_gaps == DRAW::SHOW_GAPS) {
 
920
        $gtime = array();
 
921
        $gvalue = array();
 
922
        
 
923
        $flag = 0;
 
924
        foreach ($mvalue as $idx => &$val) {
 
925
            if ($val) {
 
926
                if ($flag) $flag++;
 
927
                else {
 
928
                    array_push($gtime, $time[$idx]);
 
929
                    array_push($gvalue, $realmax);
 
930
                    $flag = 1;
 
931
                }
 
932
            } else {
 
933
                if ($flag) {
 
934
                    array_push($gtime, $time[$idx]);
 
935
                    array_push($gvalue, $realmax);
 
936
                    
 
937
                    array_push($gtime, $time[$idx]);
 
938
                    array_push($gvalue, false);
 
939
                    
 
940
                    $flag = 0;
 
941
                }
 
942
            }
 
943
        }
 
944
        
 
945
        if (sizeof($gtime) > 0) {
 
946
            $plot = new LinePlot($gvalue, $gtime);
 
947
            $plot->SetColor($GRAPH_DENSITY_PLOT_INVALID_COLOR);
 
948
            $plot->SetWeight($GRAPH_DENSITY_PLOT_INVALID_SIZE);
 
949
            $this->graph->Add($plot);
 
950
        }
 
951
    } else if ($show_gaps == DRAW::SHOW_POINTS) {
 
952
        foreach ($mvalue as &$val) {
 
953
            if ($val>1) $val = false;
 
954
            else $val = $realmax;
 
955
        }
 
956
 
 
957
        $plot = new LinePlot($mvalue, $time);
 
958
        $plot->SetColor($GRAPH_DENSITY_PLOT_VALID_COLOR);
 
959
        $plot->SetWeight($GRAPH_DENSITY_PLOT_VALID_SIZE);
 
960
 
 
961
        if ($GRAPH_DENSITY_POINTS_TYPE) {
 
962
            eval("\$mtype=$GRAPH_DENSITY_POINTS_TYPE;");
 
963
        } 
 
964
 
 
965
 
 
966
        $plot->mark->SetType($mtype);
 
967
        $plot->mark->SetColor($GRAPH_DENSITY_POINTS_OUTLINE);
 
968
        $plot->mark->SetFillColor($GRAPH_DENSITY_POINTS_COLOR);
 
969
        $plot->mark->SetSize($GRAPH_DENSITY_POINTS_SIZE);
 
970
        $this->graph->Add($plot);
 
971
 
 
972
    }
 
973
 
 
974
 
 
975
    
 
976
//    print_r($mvalue);
 
977
//    echo $realmin . "\n";
 
978
 
 
979
        
 
980
    
 
981
/*    $graph->img->SetMargin(40,110,20,40);
 
982
    //$graph ->xaxis->scale-> SetDateFormat( 'Y-m-d');
 
983
    $graph->xaxis->SetFont(FF_ARIAL,FS_NORMAL,6); 
 
984
    $graph->xaxis->SetLabelAngle(45);
 
985
    $graph->SetShadow();
 
986
 
 
987
    $graph->ygrid->Show(true,true);
 
988
$Size = sizeof($Data->TimeSeries);
 
989
for($i=3; $i<6;$i++){
 
990
    $lineplot[$i]=new LinePlot($Data->TimeSeries[$i]["Value"], $Data->TimeSeries[$i]["Time"]);
 
991
    $lineplot[$i]->SetColor($Data->TimeSeries[$i]["Color"]);
 
992
    $lineplot[$i]->SetLegend($Data->TimeSeries[$i]["Name"]);
 
993
    $graph->Add($lineplot[$i]);
 
994
}
 
995
$graph->Stroke($TempDir."Lin-".$FileName.".png");
 
996
    
 
997
*/
 
998
 
 
999
 
 
1000
 
 
1001
//        $graph = new Graph($this->width, $this->heigh /*, "auto"*/);
 
1002
//      $graph->SetScale('intlin'/* ymin, ymax, xmin, xmax */);
 
1003
        
 
1004
        // foreach masks
 
1005
//      $lineplot = new LinePlot($dataarray);
 
1006
 }
 
1007
 
 
1008
 
 
1009
 function Save($file = false) {
 
1010
    global $TMP_PATH;
 
1011
 
 
1012
    if ($this->ready) {
 
1013
        if ($file) {
 
1014
            copy($TMP_PATH . "/" .  $this->tmpfile, $file);
 
1015
            return true;
 
1016
        }
 
1017
 
 
1018
        return $this->tmpfile;
 
1019
    }
 
1020
 
 
1021
    if ($file) {
 
1022
        $this->graph->Stroke($file);
 
1023
        return true;
 
1024
    }
 
1025
 
 
1026
    $this->graph->Stroke($TMP_PATH . "/" . $this->tmpfile);
 
1027
    return $this->tmpfile;
 
1028
 }
 
1029
 
 
1030
 function GetScaleInfo() {
 
1031
/*    if (!$this->scale_coef) {
 
1032
        $f = fopen("/tmp/xxx.10", "w");
 
1033
        fwrite($f, print_r($this, true));
 
1034
        fclose($f);
 
1035
    }*/
 
1036
    return array(
 
1037
//      "a" => date("c", $this->graph->xaxis->scale->scale[1]),
 
1038
        "xmin" => dsMathPreciseAdd($this->graph->xaxis->scale->scale[0] / $this->scale_coef, $this->scale_start),
 
1039
        "xmax" => dsMathPreciseAdd($this->graph->xaxis->scale->scale[1] / $this->scale_coef, $this->scale_start),
 
1040
        "ymin" => $this->graph->yaxis->scale->scale[0],
 
1041
        "ymax" => $this->graph->yaxis->scale->scale[1]
 
1042
    );
 
1043
 }
 
1044
 
 
1045
 static function Display($file = false) {
 
1046
    global $TMP_PATH;
 
1047
    
 
1048
    if ($file) {
 
1049
        if (preg_match("/^[A-Za-z0-9\/_]\.png$/",$str)) return false;
 
1050
        return @readfile($TMP_PATH . "/" . $file);
 
1051
    }
 
1052
 
 
1053
    return false;    
 
1054
 }
 
1055
}
 
1056
 
 
1057
?>
 
 
b'\\ No newline at end of file'