diff options
Diffstat (limited to '')
-rw-r--r-- | js/RrdGraph.js | 2914 |
1 files changed, 2914 insertions, 0 deletions
diff --git a/js/RrdGraph.js b/js/RrdGraph.js new file mode 100644 index 0000000..e43fa51 --- /dev/null +++ b/js/RrdGraph.js | |||
@@ -0,0 +1,2914 @@ | |||
1 | /** | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or modify it | ||
4 | * under the terms of the GNU General Public License as published by the Free | ||
5 | * Software Foundation; either version 2 of the License, or (at your option) | ||
6 | * any later version. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | |||
13 | * You should have received a copy of the GNU General Public License along | ||
14 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
16 | |||
17 | * RRDtool 1.4.5 Copyright by Tobi Oetiker, 1997-2010 | ||
18 | * | ||
19 | * Convert to javascript: Manuel Sanmartin <manuel.luis at gmail.com> | ||
20 | **/ | ||
21 | |||
22 | "use strict"; | ||
23 | |||
24 | /** | ||
25 | * RrdGraphDescError | ||
26 | * @constructor | ||
27 | */ | ||
28 | var RrdGraphDescError = function (message) | ||
29 | { | ||
30 | this.prototype = Error.prototype; | ||
31 | this.name = "RrdGraphDescError"; | ||
32 | this.message = (message) ? message : "Error"; | ||
33 | }; | ||
34 | |||
35 | /** | ||
36 | * RrdGraphDesc | ||
37 | * @constructor | ||
38 | */ | ||
39 | var RrdGraphDesc = function (graph) | ||
40 | { | ||
41 | this.gf = null; /* graphing function */ | ||
42 | this.stack = false; /* boolean */ | ||
43 | this.debug = false; /* boolean */ | ||
44 | this.vname = null; /* name of the variable */ | ||
45 | this.vidx = Number.NaN; /* gdes reference */ | ||
46 | this.rrd = null; /* name of the rrd_file containing data */ | ||
47 | this.ds_nam = null; /* data source name */ | ||
48 | this.ds = -1; /* data source number */ | ||
49 | this.cf = RrdGraphDesc.CF_AVERAGE; /* consolidation function */ | ||
50 | this.cf_reduce = RrdGraphDesc.CF_AVERAGE; /* consolidation function for reduce_data() */ | ||
51 | this.col = null; /* graph color */ | ||
52 | this.format = null; /* format for PRINT AND GPRINT */ | ||
53 | this.legend = null; /* legend */ | ||
54 | this.strftm = false; /* should the VDEF legend be formated with strftime */ | ||
55 | this.leg_x = 0; /* location of legend */ | ||
56 | this.leg_y = 0; | ||
57 | this.yrule = Number.NaN; /* value for y rule line and for VDEF */ | ||
58 | this.xrule = 0; /* time for x rule line and for VDEF */ | ||
59 | this.vf = null; /* instruction for VDEF function */ | ||
60 | this.rpnp = null; /* instructions for CDEF function */ | ||
61 | |||
62 | /* SHIFT implementation */ | ||
63 | this.shidx = 0; /* gdes reference for offset (-1 --> constant) */ | ||
64 | this.shval = 0; /* offset if shidx is -1 */ | ||
65 | this.shift = 0; /* current shift applied */ | ||
66 | |||
67 | /* description of data fetched for the graph element */ | ||
68 | this.start = graph.start; /* timestaps for first and last data element */ | ||
69 | this.end = graph.end; | ||
70 | this.start_orig = graph.start; /* timestaps for first and last data element */ | ||
71 | this.end_orig = graph.end; | ||
72 | this.step = graph.step; /* time between samples */ | ||
73 | this.step_orig = graph.step; /* time between samples */ | ||
74 | this.ds_cnt = 0; /* how many data sources are there in the fetch */ | ||
75 | this.data_first = 0; /* first pointer to this data */ | ||
76 | this.ds_namv = []; /* name of datasources in the fetch. */ | ||
77 | this.data = []; /* the raw data drawn from the rrd */ | ||
78 | this.p_data = []; /* processed data, xsize elments */ | ||
79 | this.linewidth = 0; /* linewideth */ | ||
80 | |||
81 | /* dashed line stuff */ | ||
82 | this.dash = false; /* boolean, draw dashed line? */ | ||
83 | this.p_dashes = []; /* pointer do dash array which keeps the lengths of dashes */ | ||
84 | this.ndash = false; /* number of dash segments */ | ||
85 | this.offset = 0; /* dash offset along the line */ | ||
86 | |||
87 | this.txtalign = 0; /* change default alignment strategy for text */ | ||
88 | |||
89 | /** ** **/ | ||
90 | var args = []; // FIXME other way ¿? | ||
91 | var type = arguments[1] | ||
92 | args[0] = arguments[0]; | ||
93 | for(var i = 2; i < arguments.length; i++) args[i-1] = arguments[i]; | ||
94 | |||
95 | switch (type) { | ||
96 | case RrdGraphDesc.GF_GPRINT: | ||
97 | this.gprint.apply(this, args); | ||
98 | break; | ||
99 | case RrdGraphDesc.GF_COMMENT: | ||
100 | this.comment.apply(this, args); | ||
101 | break; | ||
102 | case RrdGraphDesc.GF_HRULE: | ||
103 | this.hrule.apply(this, args); | ||
104 | break; | ||
105 | case RrdGraphDesc.GF_VRULE: | ||
106 | this.vrule.apply(this, args); | ||
107 | break; | ||
108 | case RrdGraphDesc.GF_LINE: | ||
109 | this.line.apply(this, args); | ||
110 | break; | ||
111 | case RrdGraphDesc.GF_AREA: | ||
112 | this.area.apply(this, args); | ||
113 | break; | ||
114 | case RrdGraphDesc.GF_TICK: | ||
115 | this.tick.apply(this, args); | ||
116 | break; | ||
117 | case RrdGraphDesc.GF_TEXTALIGN: | ||
118 | this.textaling.apply(this, args); | ||
119 | break; | ||
120 | case RrdGraphDesc.GF_DEF: | ||
121 | this.def.apply(this, args); | ||
122 | break; | ||
123 | case RrdGraphDesc.GF_CDEF: | ||
124 | this.cdef.apply(this, args); | ||
125 | break; | ||
126 | case RrdGraphDesc.GF_VDEF: | ||
127 | this.vdef.apply(this, args); | ||
128 | break; | ||
129 | case RrdGraphDesc.GF_SHIFT: | ||
130 | this.fshift.apply(this, args); | ||
131 | break; | ||
132 | } | ||
133 | }; | ||
134 | |||
135 | RrdGraphDesc.GF_PRINT = 0; | ||
136 | RrdGraphDesc.GF_GPRINT = 1; | ||
137 | RrdGraphDesc.GF_COMMENT = 2; | ||
138 | RrdGraphDesc.GF_HRULE = 3; | ||
139 | RrdGraphDesc.GF_VRULE = 4; | ||
140 | RrdGraphDesc.GF_LINE = 5; | ||
141 | RrdGraphDesc.GF_AREA = 6; | ||
142 | RrdGraphDesc.GF_STACK = 7; | ||
143 | RrdGraphDesc.GF_TICK = 8; | ||
144 | RrdGraphDesc.GF_TEXTALIGN = 9; | ||
145 | RrdGraphDesc.GF_DEF = 10; | ||
146 | RrdGraphDesc.GF_CDEF = 11; | ||
147 | RrdGraphDesc.GF_VDEF = 12; | ||
148 | RrdGraphDesc.GF_SHIFT = 13; | ||
149 | RrdGraphDesc.GF_XPORT = 14; | ||
150 | |||
151 | RrdGraphDesc.CF_AVERAGE = 0; | ||
152 | RrdGraphDesc.CF_MINIMUM = 1; | ||
153 | RrdGraphDesc.CF_MAXIMUM = 2; | ||
154 | RrdGraphDesc.CF_LAST = 3; | ||
155 | RrdGraphDesc.CF_HWPREDICT = 4; | ||
156 | RrdGraphDesc.CF_SEASONAL = 5; | ||
157 | RrdGraphDesc.CF_DEVPREDICT = 6; | ||
158 | RrdGraphDesc.CF_DEVSEASONAL = 7; | ||
159 | RrdGraphDesc.CF_FAILURES = 8; | ||
160 | RrdGraphDesc.CF_MHWPREDICT = 9; | ||
161 | |||
162 | RrdGraphDesc.TXA_LEFT = 0; | ||
163 | RrdGraphDesc.TXA_RIGHT = 1; | ||
164 | RrdGraphDesc.TXA_CENTER = 2; | ||
165 | RrdGraphDesc.TXA_JUSTIFIED = 3; | ||
166 | |||
167 | RrdGraphDesc.cf_conv = function (str) | ||
168 | { | ||
169 | switch (str){ | ||
170 | case 'AVERAGE': return RrdGraphDesc.CF_AVERAGE; | ||
171 | case 'MIN': return RrdGraphDesc.CF_MINIMUM; | ||
172 | case 'MAX': return RrdGraphDesc.CF_MAXIMUM; | ||
173 | case 'LAST': return RrdGraphDesc.CF_LAST; | ||
174 | case 'HWPREDICT': return RrdGraphDesc.CF_HWPREDICT; | ||
175 | case 'MHWPREDICT': return RrdGraphDesc.CF_MHWPREDICT; | ||
176 | case 'DEVPREDICT': return RrdGraphDesc.CF_DEVPREDICT; | ||
177 | case 'SEASONAL': return RrdGraphDesc.CF_SEASONAL; | ||
178 | case 'DEVSEASONAL': return RrdGraphDesc.CF_DEVSEASONAL; | ||
179 | case 'FAILURES': return RrdGraphDesc.CF_FAILURES; | ||
180 | } | ||
181 | return -1; | ||
182 | }; | ||
183 | |||
184 | RrdGraphDesc.cf2str = function (cf) | ||
185 | { | ||
186 | switch (cf){ | ||
187 | case RrdGraphDesc.CF_AVERAGE: return 'AVERAGE'; | ||
188 | case RrdGraphDesc.CF_MINIMUM: return 'MIN'; | ||
189 | case RrdGraphDesc.CF_MAXIMUM: return 'MAX'; | ||
190 | case RrdGraphDesc.CF_LAST: return 'LAST'; | ||
191 | case RrdGraphDesc.CF_HWPREDICT: return 'HWPREDICT'; | ||
192 | case RrdGraphDesc.CF_MHWPREDICT: return 'MHWPREDICT'; | ||
193 | case RrdGraphDesc.CF_DEVPREDICT: return 'DEVPREDICT'; | ||
194 | case RrdGraphDesc.CF_SEASONAL: return 'SEASONAL'; | ||
195 | case RrdGraphDesc.CF_DEVSEASONAL: return 'DEVSEASONAL'; | ||
196 | case RrdGraphDesc.CF_FAILURES: return 'FAILURES'; | ||
197 | } | ||
198 | return ''; | ||
199 | }; | ||
200 | |||
201 | RrdGraphDesc.prototype.def = function (graph, vname, rrdfile, name, cf, step, start, end, reduce) | ||
202 | { | ||
203 | var start_t = new RrdTime(this.start); | ||
204 | var end_t = new RrdTime(this.end); | ||
205 | |||
206 | this.gf = RrdGraphDesc.GF_DEF; | ||
207 | this.vname = vname; | ||
208 | this.vidx = graph.find_var(vname); | ||
209 | this.rrd = rrdfile; | ||
210 | this.ds_nam = name; | ||
211 | this.cf = RrdGraphDesc.cf_conv(cf); | ||
212 | |||
213 | if (step != undefined && step != null) | ||
214 | this.step = step; | ||
215 | if (start != undefined && start != null) | ||
216 | start_t = new RrdTime(start); | ||
217 | if (end != undefined && end != null) | ||
218 | end_t = new RrdTime(end); | ||
219 | if (reduce === undefined || reduce === null) | ||
220 | this.cf_reduce = this.cf; // ¿? | ||
221 | else | ||
222 | this.cf_reduce = RrdGraphDesc.cf_conv(reduce); | ||
223 | this.legend = ''; | ||
224 | |||
225 | var start_end = RrdTime.proc_start_end(start_t, end_t); // FIXME here? | ||
226 | this.start = start_end[0]; | ||
227 | this.end = start_end[1]; | ||
228 | this.start_orig = start_end[0]; | ||
229 | this.end_orig = start_end[1]; | ||
230 | }; | ||
231 | |||
232 | RrdGraphDesc.prototype.cdef = function (graph, vname, rpn) | ||
233 | { | ||
234 | this.gf = RrdGraphDesc.GF_CDEF; | ||
235 | this.vname = vname; | ||
236 | this.vidx = graph.find_var(vname); | ||
237 | this.rpnp = new RrdRpn(rpn, graph.gdes); | ||
238 | this.legend = ''; | ||
239 | }; | ||
240 | |||
241 | RrdGraphDesc.prototype.vdef = function (graph, vname, rpn) | ||
242 | { | ||
243 | this.gf = RrdGraphDesc.GF_VDEF; | ||
244 | this.vname = vname; | ||
245 | |||
246 | var index = rpn.indexOf(','); | ||
247 | var name = rpn.substring(0,index); | ||
248 | this.vidx = graph.find_var(name); // FIXME checks | ||
249 | if (graph.gdes[this.vidx].gf != RrdGraphDesc.GF_DEF && graph.gdes[this.vidx].gf != RrdGraphDesc.GF_CDEF) { | ||
250 | throw new RrdGraphDescError('variable "'+name+'" not DEF nor CDEF in VDEF.'); | ||
251 | } | ||
252 | this.vf = new RrdVdef(name, rpn.substring(index+1)); | ||
253 | this.legend = ''; | ||
254 | }; | ||
255 | |||
256 | RrdGraphDesc.prototype.fshift = function (graph, vname, offset) | ||
257 | { | ||
258 | this.gf = RrdGraphDesc.GF_SHIFT; | ||
259 | this.vname = vname; // ¿? | ||
260 | this.vidx = graph.find_var(vname); // FIXME checks | ||
261 | |||
262 | if (graph.gdes[this.vidx].gf === RrdGraphDesc.GF_VDEF) | ||
263 | throw new RrdGraphDescError("Cannot shift a VDEF: '%s' in line '"+graph.gdes[this.vidx].vname+"'"); | ||
264 | if (graph.gdes[this.vidx].gf !== RrdGraphDesc.GF_DEF && graph.gdes[this.vidx].gf !== RrdGraphDesc.GF_CDEF) | ||
265 | throw new RrdGraphDescError("Encountered unknown type variable '"+graph.gdes[this.vidx].vname+"'"); | ||
266 | |||
267 | this.shidx = graph.find_var(offset); | ||
268 | if (this.shidx >= 0) { | ||
269 | if (graph.gdes[gdp.shidx].gf === RrdGraphDesc.GF_DEF || graph.gdes[gdp.shidx].gf === RrdGraphDesc.GF_CDEF) | ||
270 | throw new RrdGraphDescError("Offset cannot be a (C)DEF: '"+graph.gdes[gdp.shidx].gf+"'"); | ||
271 | if (graph.gdes[gdp.shidx].gf !== RrdGraphDesc.GF_VDEF) | ||
272 | throw new RrdGraphDescError("Encountered unknown type variable '"+graph.gdes[gdp.shidx].vname+"'"); | ||
273 | } else { | ||
274 | this.shval = parseInt(offset, 10); // FIXME check | ||
275 | this.shidx = -1; | ||
276 | } | ||
277 | this.legend = ''; | ||
278 | }; | ||
279 | |||
280 | RrdGraphDesc.prototype.line = function (graph, width, value, color, legend, stack) | ||
281 | { | ||
282 | this.gf = RrdGraphDesc.GF_LINE; | ||
283 | this.vname = value; | ||
284 | this.vidx = graph.find_var(value); | ||
285 | this.linewidth = width; | ||
286 | this.col = color; | ||
287 | if (legend === undefined) this.legend = ''; | ||
288 | else this.legend = ' '+legend; | ||
289 | if (stack === undefined) this.stack = false; | ||
290 | else this.stack = stack; | ||
291 | this.format = this.legend; | ||
292 | }; | ||
293 | |||
294 | RrdGraphDesc.prototype.area = function (graph, value, color, legend, stack) | ||
295 | { | ||
296 | this.gf = RrdGraphDesc.GF_AREA; | ||
297 | this.vname = value; | ||
298 | this.vidx = graph.find_var(value); | ||
299 | this.col = color; | ||
300 | if (legend === undefined) this.legend = ''; | ||
301 | else this.legend = ' '+legend; | ||
302 | if (stack === undefined) this.stack = false; | ||
303 | else this.stack = stack; | ||
304 | this.format = this.legend; | ||
305 | }; | ||
306 | |||
307 | RrdGraphDesc.prototype.tick = function (graph, vname, color, fraction, legend) | ||
308 | { | ||
309 | this.gf = RrdGraphDesc.GF_TICK; | ||
310 | this.vname = vname; | ||
311 | this.vidx = graph.find_var(vname); | ||
312 | this.col = color; | ||
313 | if (fraction !== undefined) | ||
314 | this.yrule = fraction; | ||
315 | if (legend === undefined) this.legend = ''; | ||
316 | else this.legend = ' '+legend; | ||
317 | this.format = this.legend; | ||
318 | }; | ||
319 | |||
320 | RrdGraphDesc.prototype.gprint = function (graph, vname, cf, format, strftimefmt) | ||
321 | { | ||
322 | this.gf = RrdGraphDesc.GF_GPRINT; | ||
323 | this.vname = vname; | ||
324 | this.vidx = graph.find_var(vname); | ||
325 | this.legend = ''; | ||
326 | if (!format) { | ||
327 | this.format = cf; | ||
328 | switch (graph.gdes[this.vidx].gf) { | ||
329 | case RrdGraphDesc.GF_DEF: | ||
330 | case RrdGraphDesc.GF_CDEF: | ||
331 | this.cf = graph.gdes[this.vidx].cf; | ||
332 | break; | ||
333 | case RrdGraphDesc.GF_VDEF: | ||
334 | break; | ||
335 | default: | ||
336 | throw new RrdGraphDescError("Encountered unknown type variable "+graph.gdes[this.vidx].vname); | ||
337 | } | ||
338 | } else { | ||
339 | this.cf = RrdGraphDesc.cf_conv(cf); | ||
340 | this.format = format; | ||
341 | } | ||
342 | if (graph.gdes[this.vidx].gf === RrdGraphDesc.GF_VDEF && strftimefmt === true) | ||
343 | this.strftm = true; | ||
344 | }; | ||
345 | |||
346 | RrdGraphDesc.prototype.comment = function (graph, text) | ||
347 | { | ||
348 | this.gf = RrdGraphDesc.GF_COMMENT; | ||
349 | this.vidx = -1; | ||
350 | this.legend = text; | ||
351 | }; | ||
352 | |||
353 | RrdGraphDesc.prototype.textalign = function (graph, align) | ||
354 | { | ||
355 | this.gf = RrdGraphDesc.GF_TEXTALIGN; | ||
356 | this.vidx = -1; | ||
357 | if (align === "left") { | ||
358 | this.txtalign = RrdGraphDesc.TXA_LEFT; | ||
359 | } else if (align === "right") { | ||
360 | this.txtalign = RrdGraphDesc.TXA_RIGHT; | ||
361 | } else if (align === "justified") { | ||
362 | this.txtalign = RrdGraphDesc.TXA_JUSTIFIED; | ||
363 | } else if (align === "center") { | ||
364 | this.txtalign = RrdGraphDesc.TXA_CENTER; | ||
365 | } else { | ||
366 | throw new RrdGraphDescError("Unknown alignement type '"+align+"'"); | ||
367 | } | ||
368 | }; | ||
369 | |||
370 | RrdGraphDesc.prototype.vrule = function (graph, time, color, legend) | ||
371 | { | ||
372 | this.gf = RrdGraphDesc.GF_VRULE; | ||
373 | this.xrule = time; | ||
374 | this.col = color; | ||
375 | if (legend === undefined) this.legend = ''; | ||
376 | else this.legend = ' '+legend; | ||
377 | }; | ||
378 | |||
379 | RrdGraphDesc.prototype.hrule = function (graph, value, color, legend) | ||
380 | { | ||
381 | this.gf = RrdGraphDesc.GF_HRULE; | ||
382 | this.yrule = value; | ||
383 | this.col = color; | ||
384 | if (legend === undefined) this.legend = ''; | ||
385 | else this.legend = ' '+legend; | ||
386 | }; | ||
387 | |||
388 | /** | ||
389 | * RrdVdefError | ||
390 | * @constructor | ||
391 | */ | ||
392 | var RrdVdefError = function (message) | ||
393 | { | ||
394 | this.prototype = Error.prototype; | ||
395 | this.name = "RrdVdefError"; | ||
396 | this.message = (message) ? message : "Error"; | ||
397 | }; | ||
398 | |||
399 | /** | ||
400 | * RrdVdef | ||
401 | * @constructor | ||
402 | */ | ||
403 | var RrdVdef = function(vname, str) /* parse */ | ||
404 | { | ||
405 | var param; | ||
406 | var func; | ||
407 | var n = 0; | ||
408 | |||
409 | this.expr = str; | ||
410 | this.op = null; | ||
411 | this.param = null; | ||
412 | this.val = null; | ||
413 | this.when = null; | ||
414 | |||
415 | var index = str.indexOf(','); | ||
416 | if (index != -1) { | ||
417 | param = parseFloat(str.substr(0,index)); | ||
418 | func = str.substr(index+1); | ||
419 | } else { | ||
420 | param = Number.NaN; | ||
421 | func = str; | ||
422 | } | ||
423 | |||
424 | if (func === 'PERCENT') this.op = RrdVdef.VDEF_PERCENT; | ||
425 | else if (func === 'PERCENTNAN') this.op = RrdVdef.VDEF_PERCENTNAN; | ||
426 | else if (func === 'MAXIMUM') this.op = RrdVdef.VDEF_MAXIMUM; | ||
427 | else if (func === 'AVERAGE') this.op = RrdVdef.VDEF_AVERAGE; | ||
428 | else if (func === 'STDEV') this.op = RrdVdef.VDEF_STDEV; | ||
429 | else if (func === 'MINIMUM') this.op = RrdVdef.VDEF_MINIMUM; | ||
430 | else if (func === 'TOTAL') this.op = RrdVdef.VDEF_TOTAL; | ||
431 | else if (func === 'FIRST') this.op = RrdVdef.VDEF_FIRST; | ||
432 | else if (func === 'LAST') this.op = RrdVdef.VDEF_LAST; | ||
433 | else if (func === 'LSLSLOPE') this.op = RrdVdef.VDEF_LSLSLOPE; | ||
434 | else if (func === 'LSLINT') this.op = RrdVdef.VDEF_LSLINT; | ||
435 | else if (func === 'LSLCORREL') this.op = RrdVdef.VDEF_LSLCORREL; | ||
436 | else { | ||
437 | throw new RrdVdefError('Unknown function "'+func+'" in VDEF "'+vame+'"'); | ||
438 | } | ||
439 | |||
440 | switch (this.op) { | ||
441 | case RrdVdef.VDEF_PERCENT: | ||
442 | case RrdVdef.VDEF_PERCENTNAN: | ||
443 | if (isNaN(param)) { /* no parameter given */ | ||
444 | throw new RrdVdefError("Function '"+func+"' needs parameter in VDEF '"+vname+"'"); | ||
445 | } | ||
446 | if (param >= 0.0 && param <= 100.0) { | ||
447 | this.param = param; | ||
448 | this.val = Number.NaN; /* undefined */ | ||
449 | this.when = 0; /* undefined */ | ||
450 | } else { | ||
451 | throw new RrdVdefError("Parameter '"+param+"' out of range in VDEF '"+vname+"'"); | ||
452 | } | ||
453 | break; | ||
454 | case RrdVdef.VDEF_MAXIMUM: | ||
455 | case RrdVdef.VDEF_AVERAGE: | ||
456 | case RrdVdef.VDEF_STDEV: | ||
457 | case RrdVdef.VDEF_MINIMUM: | ||
458 | case RrdVdef.VDEF_TOTAL: | ||
459 | case RrdVdef.VDEF_FIRST: | ||
460 | case RrdVdef.VDEF_LAST: | ||
461 | case RrdVdef.VDEF_LSLSLOPE: | ||
462 | case RrdVdef.VDEF_LSLINT: | ||
463 | case RrdVdef.VDEF_LSLCORREL: | ||
464 | if (isNaN(param)) { | ||
465 | this.param = Number.NaN; | ||
466 | this.val = Number.NaN; | ||
467 | this.when = 0; | ||
468 | } else { | ||
469 | throw new RrdVdefError("Function '"+func+"' needs no parameter in VDEF '"+vname+"'"); | ||
470 | } | ||
471 | break; | ||
472 | } | ||
473 | }; | ||
474 | |||
475 | RrdVdef.VDEF_MAXIMUM = 0; | ||
476 | RrdVdef.VDEF_MINIMUM = 1; | ||
477 | RrdVdef.VDEF_AVERAGE = 2; | ||
478 | RrdVdef.VDEF_STDEV = 3; | ||
479 | RrdVdef.VDEF_PERCENT = 4; | ||
480 | RrdVdef.VDEF_TOTAL = 5; | ||
481 | RrdVdef.VDEF_FIRST = 6; | ||
482 | RrdVdef.VDEF_LAST = 7; | ||
483 | RrdVdef.VDEF_LSLSLOPE = 8; | ||
484 | RrdVdef.VDEF_LSLINT = 9; | ||
485 | RrdVdef.VDEF_LSLCORREL = 10; | ||
486 | RrdVdef.VDEF_PERCENTNAN = 11; | ||
487 | |||
488 | RrdVdef.prototype.vdef_percent_compar = function (a, b) | ||
489 | { /* Equality is not returned; this doesn't hurt except (maybe) for a little performance. */ | ||
490 | /* NaN < -INF < finite_values < INF */ | ||
491 | if (isNaN(a)) return -1; | ||
492 | if (isNaN(b)) return 1; | ||
493 | /* NaN doesn't reach this part so INF and -INF are extremes. The sign from isinf() is compatible with the sign we return */ | ||
494 | if (!isFinite(a)) { | ||
495 | if (a === -Infinity) return -1; | ||
496 | else return 1; | ||
497 | } | ||
498 | if (!isFinite(b)) { | ||
499 | if (b === -Infinity) return -1; | ||
500 | else return 1; | ||
501 | } | ||
502 | /* If we reach this, both values must be finite */ | ||
503 | if (a < b) return -1; | ||
504 | else return 1; | ||
505 | }; | ||
506 | |||
507 | RrdVdef.prototype.calc = function(src) | ||
508 | { | ||
509 | var data; | ||
510 | var step, steps; | ||
511 | |||
512 | data = src.data; | ||
513 | steps = (src.end - src.start) / src.step; | ||
514 | |||
515 | switch (this.op) { | ||
516 | case RrdVdef.VDEF_PERCENT: | ||
517 | var array = []; | ||
518 | var field; | ||
519 | |||
520 | for (step = 0; step < steps; step++) { | ||
521 | array[step] = data[step * src.ds_cnt]; | ||
522 | } | ||
523 | array.sort(this.vdef_percent_compar); | ||
524 | field = Math.round((this.param * (steps - 1)) / 100.0); | ||
525 | this.val = array[field]; | ||
526 | this.when = 0; /* no time component */ | ||
527 | break; | ||
528 | case RrdVdef.VDEF_PERCENTNAN: | ||
529 | var array = []; | ||
530 | var field; | ||
531 | |||
532 | field=0; | ||
533 | for (step = 0; step < steps; step++) { | ||
534 | if (!isNaN(data[step * src.ds_cnt])) { | ||
535 | array[field] = data[step * src.ds_cnt]; | ||
536 | } | ||
537 | } | ||
538 | array.sort(vdef_percent_compar); | ||
539 | field = Math.round(this.param * (field - 1) / 100.0); | ||
540 | his.val = array[field]; | ||
541 | this.when = 0; /* no time component */ | ||
542 | break; | ||
543 | case RrdVdef.VDEF_MAXIMUM: | ||
544 | step = 0; | ||
545 | while (step != steps && isNaN(data[step * src.ds_cnt])) step++; | ||
546 | if (step === steps) { | ||
547 | this.val = Number.NaN; | ||
548 | this.when = 0; | ||
549 | } else { | ||
550 | this.val = data[step * src.ds_cnt]; | ||
551 | this.when = src.start + (step + 1) * src.step; | ||
552 | } | ||
553 | while (step != steps) { | ||
554 | if (isFinite(data[step * src.ds_cnt])) { | ||
555 | if (data[step * src.ds_cnt] > this.val) { | ||
556 | this.val = data[step * src.ds_cnt]; | ||
557 | this.when = src.start + (step + 1) * src.step; | ||
558 | } | ||
559 | } | ||
560 | step++; | ||
561 | } | ||
562 | break; | ||
563 | case RrdVdef.VDEF_TOTAL: | ||
564 | case RrdVdef.VDEF_STDEV: | ||
565 | case RrdVdef.VDEF_AVERAGE: | ||
566 | var cnt = 0; | ||
567 | var sum = 0.0; | ||
568 | var average = 0.0; | ||
569 | |||
570 | for (step = 0; step < steps; step++) { | ||
571 | if (isFinite(data[step * src.ds_cnt])) { | ||
572 | sum += data[step * src.ds_cnt]; | ||
573 | cnt++; | ||
574 | } | ||
575 | } | ||
576 | |||
577 | if (cnt) { | ||
578 | if (this.op === RrdVdef.VDEF_TOTAL) { | ||
579 | this.val = sum * src.step; | ||
580 | this.when = 0; /* no time component */ | ||
581 | } else if (this.op === RrdVdef.VDEF_AVERAGE) { | ||
582 | this.val = sum / cnt; | ||
583 | this.when = 0; /* no time component */ | ||
584 | } else { | ||
585 | average = sum / cnt; | ||
586 | sum = 0.0; | ||
587 | for (step = 0; step < steps; step++) { | ||
588 | if (isFinite(data[step * src.ds_cnt])) { | ||
589 | sum += Math.pow((data[step * src.ds_cnt] - average), 2.0); | ||
590 | } | ||
591 | } | ||
592 | this.val = Math.pow(sum / cnt, 0.5); | ||
593 | this.when = 0; /* no time component */ | ||
594 | } | ||
595 | } else { | ||
596 | this.val = Number.NaN; | ||
597 | this.when = 0; | ||
598 | } | ||
599 | break; | ||
600 | case RrdVdef.VDEF_MINIMUM: | ||
601 | step = 0; | ||
602 | while (step != steps && isNaN(data[step * src.ds_cnt])) step++; | ||
603 | if (step === steps) { | ||
604 | this.val = Number.NaN; | ||
605 | this.when = 0; | ||
606 | } else { | ||
607 | this.val = data[step * src.ds_cnt]; | ||
608 | this.when = src.start + (step + 1) * src.step; | ||
609 | } | ||
610 | while (step != steps) { | ||
611 | if (isFinite(data[step * src.ds_cnt])) { | ||
612 | if (data[step * src.ds_cnt] < this.val) { | ||
613 | this.val = data[step * src.ds_cnt]; | ||
614 | this.when = src.start + (step + 1) * src.step; | ||
615 | } | ||
616 | } | ||
617 | step++; | ||
618 | } | ||
619 | break; | ||
620 | case RrdVdef.VDEF_FIRST: | ||
621 | step = 0; | ||
622 | while (step != steps && isNaN(data[step * src.ds_cnt])) step++; | ||
623 | if (step === steps) { /* all entries were NaN */ | ||
624 | this.val = Number.NaN; | ||
625 | this.when = 0; | ||
626 | } else { | ||
627 | this.val = data[step * src.ds_cnt]; | ||
628 | this.when = src.start + step * src.step; | ||
629 | } | ||
630 | break; | ||
631 | case RrdVdef.VDEF_LAST: | ||
632 | step = steps - 1; | ||
633 | while (step >= 0 && isNaN(data[step * src.ds_cnt])) step--; | ||
634 | if (step < 0) { /* all entries were NaN */ | ||
635 | this.val = Number.NaN; | ||
636 | this.when = 0; | ||
637 | } else { | ||
638 | this.val = data[step * src.ds_cnt]; | ||
639 | this.when = src.start + (step + 1) * src.step; | ||
640 | } | ||
641 | break; | ||
642 | case RrdVdef.VDEF_LSLSLOPE: | ||
643 | case RrdVdef.VDEF_LSLINT: | ||
644 | case RrdVdef.VDEF_LSLCORREL: | ||
645 | var cnt = 0; | ||
646 | var SUMx, SUMy, SUMxy, SUMxx, SUMyy, slope, y_intercept, correl; | ||
647 | |||
648 | SUMx = 0; | ||
649 | SUMy = 0; | ||
650 | SUMxy = 0; | ||
651 | SUMxx = 0; | ||
652 | SUMyy = 0; | ||
653 | |||
654 | for (step = 0; step < steps; step++) { | ||
655 | if (isFinite(data[step * src.ds_cnt])) { | ||
656 | cnt++; | ||
657 | SUMx += step; | ||
658 | SUMxx += step * step; | ||
659 | SUMxy += step * data[step * src.ds_cnt]; | ||
660 | SUMy += data[step * src.ds_cnt]; | ||
661 | SUMyy += data[step * src.ds_cnt] * data[step * src.ds_cnt]; | ||
662 | } | ||
663 | } | ||
664 | |||
665 | slope = (SUMx * SUMy - cnt * SUMxy) / (SUMx * SUMx - cnt * SUMxx); | ||
666 | y_intercept = (SUMy - slope * SUMx) / cnt; | ||
667 | correl = (SUMxy - (SUMx * SUMy) / cnt) / Math.sqrt((SUMxx - (SUMx * SUMx) / cnt) * (SUMyy - (SUMy * SUMy) / cnt)); | ||
668 | |||
669 | if (cnt) { | ||
670 | if (this.op === RrdVdef.VDEF_LSLSLOPE) { | ||
671 | this.val = slope; | ||
672 | this.when = 0; | ||
673 | } else if (this.op === RrdVdef.VDEF_LSLINT) { | ||
674 | this.val = y_intercept; | ||
675 | this.when = 0; | ||
676 | } else if (this.op === RrdVdef.VDEF_LSLCORREL) { | ||
677 | this.val = correl; | ||
678 | this.when = 0; | ||
679 | } | ||
680 | } else { | ||
681 | this.val = Number.NaN; | ||
682 | this.when = 0; | ||
683 | } | ||
684 | break; | ||
685 | } | ||
686 | return 0; | ||
687 | }; | ||
688 | |||
689 | /** | ||
690 | * RrdGraphError | ||
691 | * @constructor | ||
692 | */ | ||
693 | var RrdGraphError = function (message) | ||
694 | { | ||
695 | this.prototype = Error.prototype; | ||
696 | this.name = "RrdGraphError"; | ||
697 | this.message = (message) ? message : "Error"; | ||
698 | }; | ||
699 | |||
700 | /** | ||
701 | * RrdGraph | ||
702 | * @constructor | ||
703 | */ | ||
704 | var RrdGraph = function (gfx, data) | ||
705 | { | ||
706 | this.gfx = gfx; /* graphics object */ | ||
707 | this.data = data; /* fetch data object */ | ||
708 | |||
709 | this.minval = Number.NaN; /* extreme values in the data */ | ||
710 | this.maxval = Number.NaN; | ||
711 | /* status information */ | ||
712 | //with_markup: 0, | ||
713 | this.xorigin = 0; /* where is (0,0) of the graph */ | ||
714 | this.yorigin = 0; | ||
715 | this.xOriginTitle = 0; /* where is the origin of the title */ | ||
716 | this.yOriginTitle = 0; | ||
717 | this.xOriginLegendY = 0; /* where is the origin of the y legend */ | ||
718 | this.yOriginLegendY = 0; | ||
719 | this.xOriginLegendY2 = 0; /* where is the origin of the second y legend */ | ||
720 | this.yOriginLegendY2 = 0; | ||
721 | this.xOriginLegend = 0; /* where is the origin of the legend */ | ||
722 | this.yOriginLegend = 0; | ||
723 | this.ximg = 0; /* total size of the image */ | ||
724 | this.yimg = 0; | ||
725 | this.legendwidth = 0; /* the calculated height and width of the legend */ | ||
726 | this.legendheight = 0; | ||
727 | this.magfact = 1; /* numerical magnitude */ | ||
728 | this.symbol = null; /* magnitude symbol for y-axis */ | ||
729 | this.viewfactor = 1.0; /* how should the numbers on the y-axis be scaled for viewing ? */ | ||
730 | |||
731 | this.base = 1000; /* 1000 or 1024 depending on what we graph */ | ||
732 | |||
733 | this.start = 0; /* what time does the graph cover */ | ||
734 | this.end = 0; | ||
735 | |||
736 | this.xlab_form = null; /* format for the label on the xaxis */ | ||
737 | /* public */ | ||
738 | this.xsize = 400; /* graph area size in pixels */ | ||
739 | this.ysize = 100; | ||
740 | this.zoom = 1; | ||
741 | this.grid_dash_on = 1; | ||
742 | this.grid_dash_off = 1; | ||
743 | this.second_axis_scale = 0; /* relative to the first axis (0 to disable) */ | ||
744 | this.second_axis_shift = 0; /* how much is it shifted vs the first axis */ | ||
745 | this.second_axis_legend = null; /* label to put on the seond axis */ | ||
746 | this.second_axis_format = null; /* format for the numbers on the scond axis */ | ||
747 | this.draw_x_grid = true; /* no x-grid at all */ | ||
748 | this.draw_y_grid = true; /* no y-grid at all */ | ||
749 | this.ygridstep = Number.NaN; /* user defined step for y grid */ | ||
750 | this.ylabfact = 0; /* every how many y grid shall a label be written ? */ | ||
751 | this.draw_3d_border = 2; /* size of border in pixels, 0 for off */ | ||
752 | this.dynamic_labels = false;/* pick the label shape according to the line drawn */ | ||
753 | this.ylegend = null; /* legend along the yaxis */ | ||
754 | this.title = ''; /* title for graph */ | ||
755 | this.watermark = null; /* watermark for graph */ | ||
756 | this.tabwidth = 40; /* tabwdith */ | ||
757 | this.step = 0; /* any preference for the default step ? */ | ||
758 | this.setminval = Number.NaN; /* extreme values in the data */ | ||
759 | this.setmaxval = Number.NaN; | ||
760 | this.rigid = false; /* do not expand range even with values outside */ | ||
761 | this.gridfit = true; /* adjust y-axis range etc so all grindlines falls in integer pixel values */ | ||
762 | this.lazy = 0; /* only update the image if there is reasonable probablility that the existing one is out of date */ | ||
763 | this.legendposition = RrdGraph.LEGEND_POS_SOUTH; /* the position of the legend: north, west, south or east */ | ||
764 | this.legenddirection = RrdGraph.LEGEND_DIR_TOP_DOWN; /* The direction of the legend topdown or bottomup */ | ||
765 | this.logarithmic = false; /* scale the yaxis logarithmic */ | ||
766 | this.force_scale_min = 0; /* Force a scale--min */ | ||
767 | this.force_scale_max = 0; /* Force a scale--max */ | ||
768 | this.unitsexponent = 9999; /* 10*exponent for units on y-asis */ | ||
769 | this.unitslength = 6; /* width of the yaxis labels */ | ||
770 | this.forceleftspace = false; /* do not kill the space to the left of the y-axis if there is no grid */ | ||
771 | this.slopemode = false; /* connect the dots of the curve directly, not using a stair */ | ||
772 | this.alt_ygrid = false; /* use alternative y grid algorithm */ | ||
773 | this.alt_autoscale = false; /* use alternative algorithm to find lower and upper bounds */ | ||
774 | this.alt_autoscale_min = false; /* use alternative algorithm to find lower bounds */ | ||
775 | this.alt_autoscale_max = false; /* use alternative algorithm to find upper bounds */ | ||
776 | this.no_legend = false; /* use no legend */ | ||
777 | this.no_minor = false; /* Turn off minor gridlines */ | ||
778 | this.only_graph = false; /* use only graph */ | ||
779 | this.force_rules_legend = false; /* force printing of HRULE and VRULE legend */ | ||
780 | this.force_units = false; /* mask for all FORCE_UNITS_* flags */ | ||
781 | this.force_units_si = false; /* force use of SI units in Y axis (no effect in linear graph, SI instead of E in log graph) */ | ||
782 | this.full_size_mode = false; /* -width and -height indicate the total size of the image */ | ||
783 | this.no_rrdtool_tag = false; /* disable the rrdtool tag */ | ||
784 | |||
785 | this.xlab_user = null; | ||
786 | this.ygrid_scale = null; | ||
787 | |||
788 | this.gdes = []; | ||
789 | |||
790 | this.ytr_pixie = 0; | ||
791 | this.xtr_pixie = 0; | ||
792 | |||
793 | this.AlmostEqualBuffer = new ArrayBuffer(Float32Array.BYTES_PER_ELEMENT*2); | ||
794 | this.AlmostEqualInt = new Int32Array(this.AlmostEqualBuffer); | ||
795 | this.AlmostEqualFloat = new Float32Array(this.AlmostEqualBuffer); | ||
796 | |||
797 | this.DEFAULT_FONT = 'DejaVu Sans Mono'; //DejaVu Sans Mono ,Bitstream Vera Sans Mono,monospace,Courier', // pt -> pt=px*72/96 | ||
798 | this.MGRIDWIDTH = 0.6; | ||
799 | this.GRIDWIDTH = 0.4; | ||
800 | this.YLEGEND_ANGLE = 90.0; | ||
801 | |||
802 | this.TEXT = { | ||
803 | DEFAULT: { size: 11, font: this.DEFAULT_FONT }, | ||
804 | TITLE: { size: 12, font: this.DEFAULT_FONT }, | ||
805 | AXIS: { size: 10, font: this.DEFAULT_FONT }, | ||
806 | UNIT: { size: 11, font: this.DEFAULT_FONT }, | ||
807 | LEGEND: { size: 11, font: this.DEFAULT_FONT }, | ||
808 | WATERMARK: { size: 8, font: this.DEFAULT_FONT } | ||
809 | }; | ||
810 | |||
811 | this.GRC = { | ||
812 | CANVAS: 'rgba(255, 255, 255, 1.0)', | ||
813 | BACK: 'rgba(242,242, 242, 1.0)', | ||
814 | SHADEA: 'rgba(207, 207, 207, 1.0)', | ||
815 | SHADEB: 'rgba(158, 158, 158, 1.0)', | ||
816 | GRID: 'rgba(143, 143, 143, 0.75)', | ||
817 | MGRID: 'rgba(222, 79, 79, 0.60)', | ||
818 | FONT: 'rgba(0, 0, 0, 1.0)', | ||
819 | ARROW: 'rgba(127, 31, 31, 1.0)', | ||
820 | AXIS: 'rgba(31, 31, 31, 1.0)', | ||
821 | FRAME: 'rgba(0, 0, 0, 1.0)' | ||
822 | }; | ||
823 | |||
824 | this.xlab = [ | ||
825 | {minsec: 0, length: 0, gridtm: RrdGraph.TMT_SECOND, gridst: 30, mgridtm: RrdGraph.TMT_MINUTE, mgridst: 5, labtm: RrdGraph.TMT_MINUTE, labst: 5, precis: 0, stst: '%H:%M' } , | ||
826 | {minsec: 2, length: 0, gridtm: RrdGraph.TMT_MINUTE, gridst: 1, mgridtm: RrdGraph.TMT_MINUTE, mgridst: 5, labtm: RrdGraph.TMT_MINUTE, labst: 5, precis: 0, stst: '%H:%M' } , | ||
827 | {minsec: 5, length: 0, gridtm: RrdGraph.TMT_MINUTE, gridst: 2, mgridtm: RrdGraph.TMT_MINUTE, mgridst: 10, labtm: RrdGraph.TMT_MINUTE, labst: 10, precis: 0, stst: '%H:%M' } , | ||
828 | {minsec: 10, length: 0, gridtm: RrdGraph.TMT_MINUTE, gridst: 5,mgridtm: RrdGraph.TMT_MINUTE, mgridst: 20, labtm: RrdGraph.TMT_MINUTE, labst: 20, precis: 0, stst: '%H:%M' } , | ||
829 | {minsec: 30, length: 0, gridtm: RrdGraph.TMT_MINUTE, gridst: 10, mgridtm: RrdGraph.TMT_HOUR, mgridst: 1, labtm: RrdGraph.TMT_HOUR, labst: 1, precis: 0, stst: '%H:%M' } , | ||
830 | {minsec: 60, length: 0, gridtm: RrdGraph.TMT_MINUTE, gridst: 30, mgridtm: RrdGraph.TMT_HOUR, mgridst: 2, labtm: RrdGraph.TMT_HOUR, labst: 2, precis: 0, stst: '%H:%M' } , | ||
831 | {minsec: 60, length: 24 * 3600, gridtm: RrdGraph.TMT_MINUTE, gridst: 30, mgridtm: RrdGraph.TMT_HOUR, mgridst: 2, labtm: RrdGraph.TMT_HOUR, labst: 6, precis: 0, stst: '%a %H:%M' } , | ||
832 | {minsec: 180, length: 0, gridtm: RrdGraph.TMT_HOUR, gridst: 1, mgridtm: RrdGraph.TMT_HOUR, mgridst: 6, labtm: RrdGraph.TMT_HOUR, labst: 6, precis: 0, stst: '%H:%M' } , | ||
833 | {minsec: 180, length: 24 * 3600, gridtm: RrdGraph.TMT_HOUR, gridst: 1, mgridtm: RrdGraph.TMT_HOUR, mgridst: 6, labtm: RrdGraph.TMT_HOUR, labst: 12, precis: 0, stst: '%a %H:%M' } , | ||
834 | {minsec: 600, length: 0, gridtm: RrdGraph.TMT_HOUR, gridst: 6, mgridtm: RrdGraph.TMT_DAY, mgridst: 1, labtm: RrdGraph.TMT_DAY, labst: 1, precis: 24 * 3600, stst: '%a' } , | ||
835 | {minsec: 1200, length: 0, gridtm: RrdGraph.TMT_HOUR, gridst: 6, mgridtm: RrdGraph.TMT_DAY, mgridst: 1, labtm: RrdGraph.TMT_DAY, labst: 1, precis: 24 * 3600, stst: '%d' } , | ||
836 | {minsec: 1800, length: 0, gridtm: RrdGraph.TMT_HOUR, gridst: 12, mgridtm: RrdGraph.TMT_DAY, mgridst: 1, labtm: RrdGraph.TMT_DAY, labst: 2, precis: 24 * 3600, stst: '%a %d' }, | ||
837 | {minsec: 2400, length: 0, gridtm: RrdGraph.TMT_HOUR, gridst: 12, mgridtm: RrdGraph.TMT_DAY, mgridst: 1, labtm: RrdGraph.TMT_DAY, labst: 2, precis: 24 * 3600,stst: '%a' }, | ||
838 | {minsec: 3600, length: 0, gridtm: RrdGraph.TMT_DAY, gridst: 1, mgridtm: RrdGraph.TMT_WEEK, mgridst: 1, labtm: RrdGraph.TMT_WEEK, labst: 1, precis: 7 * 24 * 3600, stst: 'Week %V' }, | ||
839 | {minsec: 3 * 3600, length: 0, gridtm: RrdGraph.TMT_WEEK, gridst: 1, mgridtm: RrdGraph.TMT_MONTH, mgridst: 1, labtm: RrdGraph.TMT_WEEK, labst: 2, precis: 7 * 24 * 3600, stst: 'Week %V' }, | ||
840 | {minsec: 6 * 3600, length: 0, gridtm: RrdGraph.TMT_MONTH, gridst: 1, mgridtm: RrdGraph.TMT_MONTH, mgridst: 1, labtm: RrdGraph.TMT_MONTH, labst: 1, precis: 30 * 24 * 3600, stst: '%b' }, | ||
841 | {minsec: 48 * 3600,length: 0, gridtm: RrdGraph.TMT_MONTH, gridst: 1, mgridtm: RrdGraph.TMT_MONTH, mgridst: 3, labtm: RrdGraph.TMT_MONTH, labst: 3, precis: 30 * 24 * 3600, stst: '%b' }, | ||
842 | {minsec: 315360, length: 0, gridtm: RrdGraph.TMT_MONTH, gridst: 3, mgridtm: RrdGraph.TMT_YEAR, mgridst: 1, labtm: RrdGraph.TMT_YEAR, labst: 1, precis: 365 * 24 * 3600, stst: '%Y' }, | ||
843 | {minsec: 10 * 24 * 3600 , length: 0, gridtm: RrdGraph.TMT_YEAR, gridst: 1, mgridtm: RrdGraph.TMT_YEAR, mgridst: 1, labtm: RrdGraph.TMT_YEAR, labst: 1, precis: 365 * 24 * 3600, stst: '%y' }, | ||
844 | {minsec: -1, length: 0, gridtm: RrdGraph.TMT_MONTH, gridst: 0, mgridtm: RrdGraph.TMT_MONTH, mgridst: 0, labtm: RrdGraph.TMT_MONTH, labst: 0, precis: 0, stst: null } | ||
845 | ]; | ||
846 | |||
847 | this.ylab = [ | ||
848 | {grid: 0.1, lfac: [1, 2, 5, 10] } , | ||
849 | {grid: 0.2, lfac: [1, 5, 10, 20] } , | ||
850 | {grid: 0.5, lfac: [1, 2, 4, 10] } , | ||
851 | {grid: 1.0, lfac: [1, 2, 5, 10] } , | ||
852 | {grid: 2.0, lfac: [1, 5, 10, 20] } , | ||
853 | {grid: 5.0, lfac: [1, 2, 4, 10] } , | ||
854 | {grid: 10.0, lfac: [1, 2, 5, 10] } , | ||
855 | {grid: 20.0, lfac: [1, 5, 10, 20] } , | ||
856 | {grid: 50.0, lfac: [1, 2, 4, 10] } , | ||
857 | {grid: 100.0, lfac: [1, 2, 5, 10] } , | ||
858 | {grid: 200.0, lfac: [1, 5, 10, 20] } , | ||
859 | {grid: 500.0, lfac: [1, 2, 4, 10] }, | ||
860 | {grid: 0.0, lfac: [0, 0, 0, 0] } | ||
861 | ]; | ||
862 | |||
863 | this.si_symbol = [ | ||
864 | 'y', /* 10e-24 Yocto */ | ||
865 | 'z', /* 10e-21 Zepto */ | ||
866 | 'a', /* 10e-18 Atto */ | ||
867 | 'f', /* 10e-15 Femto */ | ||
868 | 'p', /* 10e-12 Pico */ | ||
869 | 'n', /* 10e-9 Nano */ | ||
870 | 'u', /* 10e-6 Micro */ | ||
871 | 'm', /* 10e-3 Milli */ | ||
872 | ' ', /* Base */ | ||
873 | 'k', /* 10e3 Kilo */ | ||
874 | 'M', /* 10e6 Mega */ | ||
875 | 'G', /* 10e9 Giga */ | ||
876 | 'T', /* 10e12 Tera */ | ||
877 | 'P', /* 10e15 Peta */ | ||
878 | 'E', /* 10e18 Exa */ | ||
879 | 'Z', /* 10e21 Zeta */ | ||
880 | 'Y' /* 10e24 Yotta */ | ||
881 | ]; | ||
882 | this.si_symbcenter = 8; | ||
883 | |||
884 | this.start_t = new RrdTime("end-24h"); | ||
885 | this.end_t = new RrdTime("now"); | ||
886 | }; | ||
887 | |||
888 | RrdGraph.TMT_SECOND = 0; | ||
889 | RrdGraph.TMT_MINUTE = 1; | ||
890 | RrdGraph.TMT_HOUR = 2; | ||
891 | RrdGraph.TMT_DAY = 3; | ||
892 | RrdGraph.TMT_WEEK = 4; | ||
893 | RrdGraph.TMT_MONTH = 5; | ||
894 | RrdGraph.TMT_YEAR = 6; | ||
895 | |||
896 | RrdGraph.GFX_H_LEFT = 1; | ||
897 | RrdGraph.GFX_H_RIGHT = 2; | ||
898 | RrdGraph.GFX_H_CENTER = 3; | ||
899 | |||
900 | RrdGraph.GFX_V_TOP = 1; | ||
901 | RrdGraph.GFX_V_BOTTOM = 2; | ||
902 | RrdGraph.GFX_V_CENTER = 3; | ||
903 | |||
904 | RrdGraph.LEGEND_POS_NORTH = 0; | ||
905 | RrdGraph.LEGEND_POS_WEST = 1; | ||
906 | RrdGraph.LEGEND_POS_SOUTH = 2; | ||
907 | RrdGraph.LEGEND_POS_EAST = 3; | ||
908 | |||
909 | RrdGraph.LEGEND_DIR_TOP_DOWN = 0; | ||
910 | RrdGraph.LEGEND_DIR_BOTTOM_UP = 1; | ||
911 | |||
912 | RrdGraph.prototype.set_default_font = function (name) | ||
913 | { | ||
914 | for (var font in this.TEXT) | ||
915 | this.TEXT[font].font = name; | ||
916 | }; | ||
917 | |||
918 | RrdGraph.prototype.parse_color = function(str) | ||
919 | { | ||
920 | var bits; | ||
921 | if ((bits = /^#?([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])$/.exec(str))) { | ||
922 | return [parseInt(bits[1]+bits[1], 16), parseInt(bits[2]+bits[2], 16), parseInt(bits[3]+bits[3], 16), 1.0]; | ||
923 | } else if ((bits = /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/.exec(str))) { | ||
924 | return [parseInt(bits[1], 16), parseInt(bits[2], 16), parseInt(bits[3], 16), 1.0]; | ||
925 | } else if ((bits = /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/.exec(str))) { | ||
926 | return [parseInt(bits[1], 16), parseInt(bits[2], 16), parseInt(bits[3], 16), parseInt(bits[4], 16)/255]; | ||
927 | } else if ((bits = /^rgb\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\)$/.exec(str))) { | ||
928 | return [parseInt(bits[1], 10), parseInt(bits[2], 10), parseInt(bits[3], 10), 1.0]; | ||
929 | } else if ((bits = /^rgba\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*([0-9.]+)\)$/.exec(str))) { | ||
930 | return [parseInt(bits[1], 10), parseInt(bits[2], 10), parseInt(bits[3], 10), parseFloat(bits[4], 10)]; | ||
931 | } else { | ||
932 | throw new RrdGraphError("Unknow color format '"+str+"'"); | ||
933 | } | ||
934 | }; | ||
935 | |||
936 | RrdGraph.prototype.color2rgba = function (color) | ||
937 | { | ||
938 | return 'rgba('+color[0]+','+color[1]+','+color[2]+','+color[3]+')'; | ||
939 | }; | ||
940 | |||
941 | RrdGraph.prototype.xtr = function (mytime) | ||
942 | { | ||
943 | if (mytime === 0) { | ||
944 | this.xtr_pixie = this.xsize / (this.end - this.start); | ||
945 | return this.xorigin; | ||
946 | } | ||
947 | return this.xorigin + this.xtr_pixie * (mytime - this.start); | ||
948 | }; | ||
949 | |||
950 | RrdGraph.prototype.ytr = function (value) | ||
951 | { | ||
952 | var yval; | ||
953 | |||
954 | if (isNaN(value)) { | ||
955 | if (!this.logarithmic) | ||
956 | this.ytr_pixie = this.ysize / (this.maxval - this.minval); | ||
957 | else | ||
958 | this.ytr_pixie = this.ysize / ((Math.log(this.maxval)/Math.LN10) - (Math.log(this.minval)/Math.LN10)); | ||
959 | yval = this.yorigin; | ||
960 | } else if (!this.logarithmic) { | ||
961 | yval = this.yorigin - this.ytr_pixie * (value - this.minval); | ||
962 | } else { | ||
963 | if (value < this.minval) { | ||
964 | yval = this.yorigin; | ||
965 | } else { | ||
966 | yval = this.yorigin - this.ytr_pixie * ((Math.log(value)/Math.LN10) - (Math.log(this.minval)/Math.LN10)); | ||
967 | } | ||
968 | } | ||
969 | return yval; | ||
970 | }; | ||
971 | |||
972 | RrdGraph.prototype.AlmostEqual2sComplement = function(A, B, maxUlps) | ||
973 | { | ||
974 | this.AlmostEqualFloat[0] = A; | ||
975 | this.AlmostEqualFloat[1] = B; | ||
976 | |||
977 | var aInt = this.AlmostEqualInt[0]; | ||
978 | if (aInt < 0) aInt = 0x80000000 - aInt; | ||
979 | |||
980 | var bInt = this.AlmostEqualInt[1]; | ||
981 | if (bInt < 0) bInt = 0x80000000 - bInt; | ||
982 | |||
983 | var intDiff = Math.abs(aInt - bInt); | ||
984 | |||
985 | if (intDiff <= maxUlps) | ||
986 | return true; | ||
987 | |||
988 | return false; | ||
989 | }; | ||
990 | |||
991 | RrdGraph.prototype.tmt2str = function (val) | ||
992 | { | ||
993 | switch (val) { | ||
994 | case RrdGraph.TMT_SECOND: return 'sec'; | ||
995 | case RrdGraph.TMT_MINUTE: return 'min'; | ||
996 | case RrdGraph.TMT_HOUR: return 'hour'; | ||
997 | case RrdGraph.TMT_DAY: return 'day'; | ||
998 | case RrdGraph.TMT_WEEK: return 'week'; | ||
999 | case RrdGraph.TMT_MONTH: return 'mon'; | ||
1000 | case RrdGraph.TMT_YEAR: return 'year'; | ||
1001 | } | ||
1002 | return val; | ||
1003 | }; | ||
1004 | |||
1005 | RrdGraph.prototype.find_first_time = function(start, baseint, basestep) | ||
1006 | { | ||
1007 | var date = new Date(start*1000); | ||
1008 | |||
1009 | switch (baseint) { | ||
1010 | case RrdGraph.TMT_SECOND: | ||
1011 | var sec = date.getSeconds(); | ||
1012 | sec -= sec % basestep; | ||
1013 | date.setSeconds(sec); | ||
1014 | break; | ||
1015 | case RrdGraph.TMT_MINUTE: | ||
1016 | date.setSeconds(0); | ||
1017 | var min = date.getMinutes(); | ||
1018 | min -= min % basestep; | ||
1019 | date.setMinutes(min); | ||
1020 | break; | ||
1021 | case RrdGraph.TMT_HOUR: | ||
1022 | date.setSeconds(0); | ||
1023 | date.setMinutes(0); | ||
1024 | var hour = date.getHours(); | ||
1025 | hour -= hour % basestep; | ||
1026 | date.setHours(hour); | ||
1027 | break; | ||
1028 | case RrdGraph.TMT_DAY: | ||
1029 | date.setSeconds(0); | ||
1030 | date.setMinutes(0); | ||
1031 | date.setHours(0); | ||
1032 | break; | ||
1033 | case RrdGraph.TMT_WEEK: | ||
1034 | date.setSeconds(0); | ||
1035 | date.setMinutes(0); | ||
1036 | date.setHours(0); | ||
1037 | var mday = date.getDate(); | ||
1038 | var wday = date.getDay(); | ||
1039 | mday -= wday - 1; // FIXME find_first_weekday | ||
1040 | if (wday === 0) mday -= 7;// FIXME find_first_weekday | ||
1041 | date.setDate(mday); | ||
1042 | break; | ||
1043 | case RrdGraph.TMT_MONTH: | ||
1044 | date.setSeconds(0); | ||
1045 | date.setMinutes(0); | ||
1046 | date.setHours(0); | ||
1047 | date.setDate(1); | ||
1048 | var mon = date.getMonth(); | ||
1049 | mon -= mon % basestep; | ||
1050 | date.setMonth(mon); | ||
1051 | break; | ||
1052 | case RrdGraph.TMT_YEAR: | ||
1053 | date.setSeconds(0); | ||
1054 | date.setMinutes(0); | ||
1055 | date.setHours(0); | ||
1056 | date.setDate(1); | ||
1057 | date.setMonth(0); | ||
1058 | var year = date.getFullYear()-1900; | ||
1059 | year -= (year + 1900) %basestep; | ||
1060 | date.setFullYear(year+1900); | ||
1061 | } | ||
1062 | return Math.round(date.getTime()/1000.0); | ||
1063 | }; | ||
1064 | |||
1065 | RrdGraph.prototype.find_next_time = function(current, baseint, basestep) | ||
1066 | { | ||
1067 | var date = new Date(current*1000); | ||
1068 | var limit = 2; | ||
1069 | var madetime; | ||
1070 | |||
1071 | switch (baseint) { | ||
1072 | case RrdGraph.TMT_SECOND: limit = 7200; break; | ||
1073 | case RrdGraph.TMT_MINUTE: limit = 120; break; | ||
1074 | case RrdGraph.TMT_HOUR: limit = 2; break; | ||
1075 | default: limit = 2; break; | ||
1076 | } | ||
1077 | |||
1078 | do { | ||
1079 | switch (baseint) { | ||
1080 | case RrdGraph.TMT_SECOND: | ||
1081 | date.setSeconds(date.getSeconds()+basestep); | ||
1082 | break; | ||
1083 | case RrdGraph.TMT_MINUTE: | ||
1084 | date.setMinutes(date.getMinutes()+basestep); | ||
1085 | break; | ||
1086 | case RrdGraph.TMT_HOUR: | ||
1087 | date.setHours(date.getHours()+basestep); | ||
1088 | break; | ||
1089 | case RrdGraph.TMT_DAY: | ||
1090 | date.setDate(date.getDate()+basestep); | ||
1091 | break; | ||
1092 | case RrdGraph.TMT_WEEK: | ||
1093 | date.setDate(date.getDate()+7*basestep); | ||
1094 | break; | ||
1095 | case RrdGraph.TMT_MONTH: | ||
1096 | date.setMonth(date.getMonth()+basestep); | ||
1097 | break; | ||
1098 | case RrdGraph.TMT_YEAR: | ||
1099 | date.setFullYear(date.getFullYear()+basestep); | ||
1100 | break; | ||
1101 | } | ||
1102 | madetime = Math.round(date.getTime()/1000.0); | ||
1103 | } while (madetime === -1 && limit-- >= 0); /* this is necessary to skip impossible times like the daylight saving time skips */ // FIXME ?? | ||
1104 | return madetime; | ||
1105 | }; | ||
1106 | |||
1107 | RrdGraph.prototype.print_calc = function() | ||
1108 | { | ||
1109 | var validsteps; | ||
1110 | var printval; | ||
1111 | var tmvdef; | ||
1112 | var graphelement = 0; | ||
1113 | var max_ii; | ||
1114 | var magfact = -1; | ||
1115 | var si_symb = ""; | ||
1116 | var percent_s; | ||
1117 | var prline_cnt = 0; | ||
1118 | |||
1119 | var now = Math.round((new Date()).getTime() / 1000); | ||
1120 | |||
1121 | for (var i = 0, gdes_c = this.gdes.length; i < gdes_c; i++) { | ||
1122 | var vidx = this.gdes[i].vidx; | ||
1123 | switch (this.gdes[i].gf) { | ||
1124 | case RrdGraphDesc.GF_PRINT: | ||
1125 | case RrdGraphDesc.GF_GPRINT: | ||
1126 | if (this.gdes[vidx].gf === RrdGraphDesc.GF_VDEF) { /* simply use vals */ | ||
1127 | printval = this.gdes[vidx].vf.val; | ||
1128 | tmvdef = this.gdes[vidx].vf.when; | ||
1129 | // localtime_r(&this.gdes[vidx].vf.when, &tmvdef); // FIXME ? | ||
1130 | } else { /* need to calculate max,min,avg etcetera */ | ||
1131 | max_ii = ((this.gdes[vidx].end - this.gdes[vidx].start) / this.gdes[vidx].step * this.gdes[vidx].ds_cnt); | ||
1132 | printval = Number.NaN; | ||
1133 | validsteps = 0; | ||
1134 | |||
1135 | for (var ii = this.gdes[vidx].ds; ii < max_ii; ii += this.gdes[vidx].ds_cnt) { | ||
1136 | if (!isFinite(this.gdes[vidx].data[ii])) continue; | ||
1137 | if (isNaN(printval)) { | ||
1138 | printval = this.gdes[vidx].data[ii]; | ||
1139 | validsteps++; | ||
1140 | continue; | ||
1141 | } | ||
1142 | switch (this.gdes[i].cf) { | ||
1143 | case RrdGraphDesc.CF_HWPREDICT: | ||
1144 | case RrdGraphDesc.CF_MHWPREDICT: | ||
1145 | case RrdGraphDesc.CF_DEVPREDICT: | ||
1146 | case RrdGraphDesc.CF_DEVSEASONAL: | ||
1147 | case RrdGraphDesc.CF_SEASONAL: | ||
1148 | case RrdGraphDesc.CF_AVERAGE: | ||
1149 | validsteps++; | ||
1150 | printval += this.gdes[vidx].data[ii]; | ||
1151 | break; | ||
1152 | case RrdGraphDesc.CF_MINIMUM: | ||
1153 | printval = Math.min(printval, this.gdes[vidx].data[ii]); | ||
1154 | break; | ||
1155 | case RrdGraphDesc.CF_FAILURES: | ||
1156 | case RrdGraphDesc.CF_MAXIMUM: | ||
1157 | printval = Math.max(printval, this.gdes[vidx].data[ii]); | ||
1158 | break; | ||
1159 | case RrdGraphDesc.CF_LAST: | ||
1160 | printval = this.gdes[vidx].data[ii]; | ||
1161 | } | ||
1162 | } | ||
1163 | if (this.gdes[i].cf === RrdGraphDesc.CF_AVERAGE || this.gdes[i].cf > RrdGraphDesc.CF_LAST) { | ||
1164 | if (validsteps > 1) printval = (printval / validsteps); | ||
1165 | } | ||
1166 | } /* prepare printval */ | ||
1167 | |||
1168 | if (!this.gdes[i].strftm && (percent_s = this.gdes[i].format.indexOf('%S')) != -1) { | ||
1169 | if (magfact < 0.0) { | ||
1170 | //[printval, si_symb, magfact] = this.auto_scale(printval, si_symb, magfact); | ||
1171 | var dummy = this.auto_scale(printval, si_symb, magfact); printval = dummy[0]; si_symb = dummy[1]; magfact = dummy[2]; | ||
1172 | if (printval === 0.0) magfact = -1.0; | ||
1173 | } else { | ||
1174 | printval /= magfact; | ||
1175 | } | ||
1176 | this.gdes[i].format = this.gdes[i].format.substr(0, percent_s+1)+'s'+this.gdes[i].format.substr(percent_s+2); | ||
1177 | } else if (!this.gdes[i].strftm && this.gdes[i].format.indexOf('%s') != -1) { | ||
1178 | //[printval, si_symb, magfact] = this.auto_scale(printval, si_symb, magfact); | ||
1179 | var dummy = this.auto_scale(printval, si_symb, magfact); printval = dummy[0]; si_symb = dummy[1]; magfact = dummy[2]; | ||
1180 | } | ||
1181 | |||
1182 | if (this.gdes[i].strftm) { | ||
1183 | this.gdes[i].legend = strftime(this.gdes[i].format, tmvdef); | ||
1184 | } else { | ||
1185 | this.gdes[i].legend = sprintf(this.gdes[i].format, printval, si_symb); | ||
1186 | } | ||
1187 | graphelement = 1; | ||
1188 | break; | ||
1189 | case RrdGraphDesc.GF_LINE: | ||
1190 | case RrdGraphDesc.GF_AREA: | ||
1191 | case RrdGraphDesc.GF_TICK: | ||
1192 | graphelement = 1; | ||
1193 | break; | ||
1194 | case RrdGraphDesc.GF_HRULE: | ||
1195 | if (isNaN(this.gdes[i].yrule)) { /* we must set this here or the legend printer can not decide to print the legend */ | ||
1196 | this.gdes[i].yrule = this.gdes[vidx].vf.val; | ||
1197 | }; | ||
1198 | graphelement = 1; | ||
1199 | break; | ||
1200 | case RrdGraphDesc.GF_VRULE: | ||
1201 | if (this.gdes[i].xrule === 0) { /* again ... the legend printer needs it */ | ||
1202 | this.gdes[i].xrule = this.gdes[vidx].vf.when; | ||
1203 | }; | ||
1204 | graphelement = 1; | ||
1205 | break; | ||
1206 | case RrdGraphDesc.GF_COMMENT: | ||
1207 | case RrdGraphDesc.GF_TEXTALIGN: | ||
1208 | case RrdGraphDesc.GF_DEF: | ||
1209 | case RrdGraphDesc.GF_CDEF: | ||
1210 | case RrdGraphDesc.GF_VDEF: | ||
1211 | case RrdGraphDesc.GF_SHIFT: | ||
1212 | case RrdGraphDesc.GF_XPORT: | ||
1213 | break; | ||
1214 | case RrdGraphDesc.GF_STACK: | ||
1215 | throw new RrdGraphError("STACK should already be turned into LINE or AREA here"); | ||
1216 | break; | ||
1217 | } | ||
1218 | } | ||
1219 | return graphelement; | ||
1220 | }; | ||
1221 | |||
1222 | RrdGraph.prototype.reduce_data = function(gdes, cur_step) | ||
1223 | { | ||
1224 | var reduce_factor = Math.ceil(gdes.step / cur_step); | ||
1225 | var col, dst_row, row_cnt, start_offset, end_offset, skiprows = 0; | ||
1226 | var srcptr, dstptr; | ||
1227 | |||
1228 | gdes.step = cur_step * reduce_factor; /* set new step size for reduced data */ | ||
1229 | dstptr = 0; | ||
1230 | srcptr = 0; | ||
1231 | row_cnt = (gdes.end - gdes.start) / cur_step; | ||
1232 | |||
1233 | end_offset = gdes.end % gdes.step; | ||
1234 | start_offset = gdes.start % gdes.step; | ||
1235 | |||
1236 | if (start_offset) { | ||
1237 | gdes.start = gdes.start - start_offset; | ||
1238 | skiprows = reduce_factor - start_offset / cur_step; | ||
1239 | srcptr += skiprows * gdes.ds_cnt; | ||
1240 | for (col = 0; col < gdes.ds_cnt; col++) | ||
1241 | gdes.data[dstptr++] = Number.NaN; | ||
1242 | row_cnt -= skiprows; | ||
1243 | } | ||
1244 | |||
1245 | if (end_offset) { | ||
1246 | gdes.end = gdes.end - end_offset + gdes.step; | ||
1247 | skiprows = end_offset / cur_step; | ||
1248 | row_cnt -= skiprows; | ||
1249 | } | ||
1250 | |||
1251 | if (row_cnt % reduce_factor) { | ||
1252 | throw new RrdGraphError("BUG in reduce_data(), SANITY CHECK: "+row_cnt+" rows cannot be reduced by "+reduce_factor); | ||
1253 | } | ||
1254 | |||
1255 | for (dst_row = 0; row_cnt >= reduce_factor; dst_row++) { | ||
1256 | for (col = 0; col < gdes.ds_cnt; col++) { | ||
1257 | var newval = Number.NaN; | ||
1258 | var validval = 0; | ||
1259 | |||
1260 | for (var i = 0; i < reduce_factor; i++) { | ||
1261 | if (isNaN(gdes.data[srcptr + i*gdes.ds_cnt + col])) continue; | ||
1262 | validval++; | ||
1263 | if (isNaN(newval)) { | ||
1264 | newval = gdes.data[srcptr + i * gdes.ds_cnt + col]; | ||
1265 | } else { | ||
1266 | switch (gdes.cf_reduce) { | ||
1267 | case RrdGraphDesc.CF_HWPREDICT: | ||
1268 | case RrdGraphDesc.CF_MHWPREDICT: | ||
1269 | case RrdGraphDesc.CF_DEVSEASONAL: | ||
1270 | case RrdGraphDesc.CF_DEVPREDICT: | ||
1271 | case RrdGraphDesc.CF_SEASONAL: | ||
1272 | case RrdGraphDesc.CF_AVERAGE: | ||
1273 | newval += gdes.data[srcptr + i*gdes.ds_cnt + col]; | ||
1274 | break; | ||
1275 | case RrdGraphDesc.CF_MINIMUM: | ||
1276 | newval = Math.min(newval, gdes.data[srcptr + i*gdes.ds_cnt + col]); | ||
1277 | break; | ||
1278 | case RrdGraphDesc.CF_FAILURES: | ||
1279 | /* an interval contains a failure if any subintervals contained a failure */ | ||
1280 | case RrdGraphDesc.CF_MAXIMUM: | ||
1281 | newval = Math.max(newval, gdes.data[srcptr + i*gdes.ds_cnt + col]); | ||
1282 | break; | ||
1283 | case RrdGraphDesc.CF_LAST: | ||
1284 | newval = gdes.data[srcptr + i*gdes.ds_cnt + col]; | ||
1285 | break; | ||
1286 | } | ||
1287 | } | ||
1288 | } | ||
1289 | |||
1290 | if (validval === 0) { | ||
1291 | newval = Number.NaN; | ||
1292 | } else { | ||
1293 | switch (gdes.cf_reduce) { | ||
1294 | case RrdGraphDesc.CF_HWPREDICT: | ||
1295 | case RrdGraphDesc.CF_MHWPREDICT: | ||
1296 | case RrdGraphDesc.CF_DEVSEASONAL: | ||
1297 | case RrdGraphDesc.CF_DEVPREDICT: | ||
1298 | case RrdGraphDesc.CF_SEASONAL: | ||
1299 | case RrdGraphDesc.CF_AVERAGE: | ||
1300 | newval /= validval; | ||
1301 | break; | ||
1302 | case RrdGraphDesc.CF_MINIMUM: | ||
1303 | case RrdGraphDesc.CF_FAILURES: | ||
1304 | case RrdGraphDesc.CF_MAXIMUM: | ||
1305 | case RrdGraphDesc.CF_LAST: | ||
1306 | break; | ||
1307 | } | ||
1308 | } | ||
1309 | gdes.data[dstptr++] = newval; | ||
1310 | } | ||
1311 | |||
1312 | srcptr += gdes.ds_cnt * reduce_factor; | ||
1313 | row_cnt -= reduce_factor; | ||
1314 | } | ||
1315 | if (end_offset) { | ||
1316 | for (col = 0; col < gdes.ds_cnt; col++) | ||
1317 | gdes.data[dstptr++] = Number.NaN; | ||
1318 | } | ||
1319 | }; | ||
1320 | |||
1321 | RrdGraph.prototype.data_fetch = function() | ||
1322 | { | ||
1323 | var skip; | ||
1324 | |||
1325 | for (var i = 0, gdes_c = this.gdes.length; i < gdes_c; i++) { | ||
1326 | if (this.gdes[i].gf != RrdGraphDesc.GF_DEF) continue; | ||
1327 | |||
1328 | skip = false; | ||
1329 | for (var ii = 0; ii < i; ii++) { | ||
1330 | if (this.gdes[ii].gf != RrdGraphDesc.GF_DEF) continue; | ||
1331 | if ((this.gdes[i].rrd === this.gdes[ii].rrd) | ||
1332 | && (this.gdes[i].cf === this.gdes[ii].cf) | ||
1333 | && (this.gdes[i].cf_reduce === this.gdes[ii].cf_reduce) | ||
1334 | && (this.gdes[i].start_orig === this.gdes[ii].start_orig) | ||
1335 | && (this.gdes[i].end_orig === this.gdes[ii].end_orig) | ||
1336 | && (this.gdes[i].step_orig === this.gdes[ii].step_orig)) { | ||
1337 | this.gdes[i].start = this.gdes[ii].start; | ||
1338 | this.gdes[i].end = this.gdes[ii].end; | ||
1339 | this.gdes[i].step = this.gdes[ii].step; | ||
1340 | this.gdes[i].ds_cnt = this.gdes[ii].ds_cnt; | ||
1341 | this.gdes[i].ds_namv = this.gdes[ii].ds_namv; | ||
1342 | this.gdes[i].data = this.gdes[ii].data; | ||
1343 | this.gdes[i].data_first = 0; | ||
1344 | skip = true; | ||
1345 | } | ||
1346 | if (skip) break; | ||
1347 | } | ||
1348 | |||
1349 | if (!skip) { | ||
1350 | var ft_step = this.gdes[i].step; /* ft_step will record what we got from fetch */ | ||
1351 | ft_step = this.data.fetch(this.gdes[i], ft_step); | ||
1352 | if (ft_step < 0) | ||
1353 | return -1; | ||
1354 | this.gdes[i].data_first = 1; | ||
1355 | // this.gdes[i].step = Math.max(this.gdes[i].step, this.step); // FIXME | ||
1356 | if (ft_step < this.gdes[i].step) { | ||
1357 | this.reduce_data(this.gdes[i], ft_step); | ||
1358 | } else { | ||
1359 | this.gdes[i].step = ft_step; | ||
1360 | } | ||
1361 | } | ||
1362 | /* lets see if the required data source is really there */ | ||
1363 | for (var ii = 0; ii < this.gdes[i].ds_cnt; ii++) { | ||
1364 | if (this.gdes[i].ds_namv[ii] === this.gdes[i].ds_nam) { | ||
1365 | this.gdes[i].ds = ii; | ||
1366 | break; | ||
1367 | } | ||
1368 | } | ||
1369 | |||
1370 | if (this.gdes[i].ds === -1) | ||
1371 | throw new RrdGraphError("No DS called '"+this.gdes[i].ds_nam+"' in '"+this.gdes[i].rrd+"'"); | ||
1372 | } | ||
1373 | |||
1374 | return 0; | ||
1375 | }; | ||
1376 | |||
1377 | RrdGraph.prototype.lcd = function (num) | ||
1378 | { | ||
1379 | var rest; | ||
1380 | for (var i = 0; num[i + 1] != 0; i++) { | ||
1381 | do { | ||
1382 | rest = num[i] % num[i + 1]; | ||
1383 | num[i] = num[i + 1]; | ||
1384 | num[i + 1] = rest; | ||
1385 | } while (rest != 0); // FIXME infinite loop ? | ||
1386 | num[i + 1] = num[i]; | ||
1387 | } | ||
1388 | return num[i]; | ||
1389 | }; | ||
1390 | |||
1391 | RrdGraph.prototype.data_calc = function() | ||
1392 | { | ||
1393 | var dataidx; | ||
1394 | var now; | ||
1395 | var rpnstack; | ||
1396 | |||
1397 | for (var gdi = 0, gdes_c = this.gdes.length; gdi < gdes_c; gdi++) { | ||
1398 | switch (this.gdes[gdi].gf) { | ||
1399 | case RrdGraphDesc.GF_XPORT: | ||
1400 | break; | ||
1401 | case RrdGraphDesc.GF_SHIFT: | ||
1402 | var vdp = this.gdes[this.gdes[gdi].vidx]; | ||
1403 | /* remove current shift */ | ||
1404 | vdp.start -= vdp.shift; | ||
1405 | vdp.end -= vdp.shift; | ||
1406 | |||
1407 | if (this.gdes[gdi].shidx >= 0) vdp.shift = this.gdes[this.gdes[gdi].shidx].vf.val; | ||
1408 | else vdp.shift = this.gdes[gdi].shval; | ||
1409 | |||
1410 | vdp.shift = (vdp.shift / vdp.step) * vdp.step; | ||
1411 | |||
1412 | vdp.start += vdp.shift; | ||
1413 | vdp.end += vdp.shift; | ||
1414 | break; | ||
1415 | case RrdGraphDesc.GF_VDEF: | ||
1416 | this.gdes[gdi].ds_cnt = 0; | ||
1417 | if (this.gdes[gdi].vf.calc(this.gdes[this.gdes[gdi].vidx])) | ||
1418 | throw new RrdGraphError("Error processing VDEF '"+this.gdes[gdi].vname+"'"); | ||
1419 | break; | ||
1420 | case RrdGraphDesc.GF_CDEF: | ||
1421 | this.gdes[gdi].ds_cnt = 1; | ||
1422 | this.gdes[gdi].ds = 0; | ||
1423 | this.gdes[gdi].data_first = 1; | ||
1424 | this.gdes[gdi].start = 0; | ||
1425 | this.gdes[gdi].end = 0; | ||
1426 | var steparray = []; | ||
1427 | var stepcnt = 0; | ||
1428 | dataidx = -1; | ||
1429 | |||
1430 | var rpnp = this.gdes[gdi].rpnp.rpnp; | ||
1431 | for (var rpi = 0; rpnp[rpi].op != RrdRpn.OP_END; rpi++) { | ||
1432 | if (rpnp[rpi].op === RrdRpn.OP_VARIABLE || rpnp[rpi].op === RrdRpn.OP_PREV_OTHER) { | ||
1433 | var ptr = rpnp[rpi].ptr; | ||
1434 | if (this.gdes[ptr].ds_cnt === 0) { /* this is a VDEF data source */ | ||
1435 | rpnp[rpi].val = this.gdes[ptr].vf.val; | ||
1436 | rpnp[rpi].op = RrdRpn.OP_NUMBER; | ||
1437 | } else { /* normal variables and PREF(variables) */ | ||
1438 | ++stepcnt; | ||
1439 | steparray[stepcnt - 1] = this.gdes[ptr].step; | ||
1440 | |||
1441 | if (this.gdes[gdi].start < this.gdes[ptr].start) | ||
1442 | this.gdes[gdi].start = this.gdes[ptr].start; | ||
1443 | if (this.gdes[gdi].end === 0 || this.gdes[gdi].end > this.gdes[ptr].end) | ||
1444 | this.gdes[gdi].end = this.gdes[ptr].end; | ||
1445 | |||
1446 | rpnp[rpi].data = this.gdes[ptr].data; | ||
1447 | rpnp[rpi].pdata = this.gdes[ptr].ds; | ||
1448 | rpnp[rpi].step = this.gdes[ptr].step; | ||
1449 | rpnp[rpi].ds_cnt = this.gdes[ptr].ds_cnt; | ||
1450 | } | ||
1451 | } | ||
1452 | } | ||
1453 | /* move the data pointers to the correct period */ | ||
1454 | for (var rpi = 0; rpnp[rpi].op != RrdRpn.OP_END; rpi++) { | ||
1455 | if (rpnp[rpi].op === RrdRpn.OP_VARIABLE || rpnp[rpi].op === RrdRpn.OP_PREV_OTHER) { | ||
1456 | var ptr = rpnp[rpi].ptr; | ||
1457 | var diff = this.gdes[gdi].start - this.gdes[ptr].start; | ||
1458 | |||
1459 | if (diff > 0) rpnp[rpi].pdata += (diff / this.gdes[ptr].step) * this.gdes[ptr].ds_cnt; | ||
1460 | } | ||
1461 | } | ||
1462 | |||
1463 | if (steparray === null) { | ||
1464 | throw new RrdGraphError("rpn expressions without DEF or CDEF variables are not supported"); | ||
1465 | } | ||
1466 | steparray[stepcnt] = 0; | ||
1467 | this.gdes[gdi].step = this.lcd(steparray); | ||
1468 | this.gdes[gdi].data = []; | ||
1469 | |||
1470 | for (now = this.gdes[gdi].start + this.gdes[gdi].step; now <= this.gdes[gdi].end; now += this.gdes[gdi].step) { | ||
1471 | if (this.gdes[gdi].rpnp.calc(now, this.gdes[gdi].data, ++dataidx) === -1) | ||
1472 | return -1; | ||
1473 | } | ||
1474 | break; | ||
1475 | default: | ||
1476 | continue; | ||
1477 | } | ||
1478 | } | ||
1479 | return 0; | ||
1480 | }; | ||
1481 | |||
1482 | RrdGraph.prototype.data_proc = function() | ||
1483 | { | ||
1484 | var pixstep = (this.end - this.start) / this.xsize; | ||
1485 | var paintval; | ||
1486 | var minval = Number.NaN, maxval = Number.NaN; | ||
1487 | var gr_time; | ||
1488 | |||
1489 | /* memory for the processed data */ | ||
1490 | |||
1491 | for (var i = 0, gdes_c = this.gdes.length; i < gdes_c; i++) { | ||
1492 | if ((this.gdes[i].gf === RrdGraphDesc.GF_LINE) || (this.gdes[i].gf === RrdGraphDesc.GF_AREA) || (this.gdes[i].gf === RrdGraphDesc.GF_TICK)) { | ||
1493 | this.gdes[i].p_data = []; | ||
1494 | } | ||
1495 | } | ||
1496 | |||
1497 | for (var i = 0; i < this.xsize; i++) { /* for each pixel */ | ||
1498 | var vidx; | ||
1499 | gr_time = this.start + pixstep * i; /* time of the current step */ | ||
1500 | paintval = 0.0; | ||
1501 | |||
1502 | for (var ii = 0 , gdes_c = this.gdes.length; ii < gdes_c; ii++) { | ||
1503 | var value; | ||
1504 | switch (this.gdes[ii].gf) { | ||
1505 | case RrdGraphDesc.GF_LINE: | ||
1506 | case RrdGraphDesc.GF_AREA: | ||
1507 | case RrdGraphDesc.GF_TICK: | ||
1508 | if (!this.gdes[ii].stack) paintval = 0.0; | ||
1509 | value = this.gdes[ii].yrule; | ||
1510 | if (isNaN(value) || (this.gdes[ii].gf === RrdGraphDesc.GF_TICK)) { | ||
1511 | vidx = this.gdes[ii].vidx; | ||
1512 | if (this.gdes[vidx].gf === RrdGraphDesc.GF_VDEF) { | ||
1513 | value = this.gdes[vidx].vf.val; | ||
1514 | } else if (gr_time >= this.gdes[vidx].start && gr_time < this.gdes[vidx].end) { | ||
1515 | value = this.gdes[vidx].data[Math.floor((gr_time - this.gdes[vidx].start) / this.gdes[vidx].step) * this.gdes[vidx].ds_cnt + this.gdes[vidx].ds]; | ||
1516 | } else { | ||
1517 | value = Number.NaN; | ||
1518 | } | ||
1519 | } | ||
1520 | if (!isNaN(value)) { | ||
1521 | paintval += value; | ||
1522 | this.gdes[ii].p_data[i] = paintval; | ||
1523 | if (isFinite(paintval) && this.gdes[ii].gf != RrdGraphDesc.GF_TICK) { | ||
1524 | if ((isNaN(minval) || paintval < minval) && !(this.logarithmic && paintval <= 0.0)) | ||
1525 | minval = paintval; | ||
1526 | if (isNaN(maxval) || paintval > maxval) | ||
1527 | maxval = paintval; | ||
1528 | } | ||
1529 | } else { | ||
1530 | this.gdes[ii].p_data[i] = Number.NaN; | ||
1531 | } | ||
1532 | break; | ||
1533 | case RrdGraphDesc.GF_STACK: | ||
1534 | throw new RrdGraphError("STACK should already be turned into LINE or AREA here"); | ||
1535 | break; | ||
1536 | default: | ||
1537 | break; | ||
1538 | } | ||
1539 | } | ||
1540 | } | ||
1541 | |||
1542 | if (this.logarithmic) { | ||
1543 | if (isNaN(minval) || isNaN(maxval) || maxval <= 0) { | ||
1544 | minval = 0.0; | ||
1545 | maxval = 5.1; | ||
1546 | } | ||
1547 | if (minval <= 0) minval = maxval / 10e8; | ||
1548 | } else { | ||
1549 | if (isNaN(minval) || isNaN(maxval)) { | ||
1550 | minval = 0.0; | ||
1551 | maxval = 1.0; | ||
1552 | } | ||
1553 | } | ||
1554 | |||
1555 | if (isNaN(this.minval) || ((!this.rigid) && this.minval > minval)) { | ||
1556 | if (this.logarithmic) this.minval = minval / 2.0; | ||
1557 | else this.minval = minval; | ||
1558 | } | ||
1559 | if (isNaN(this.maxval) || (!this.rigid && this.maxval < maxval)) { | ||
1560 | if (this.logarithmic) this.maxval = maxval * 2.0; | ||
1561 | else this.maxval = maxval; | ||
1562 | } | ||
1563 | |||
1564 | if (this.minval > this.maxval) { | ||
1565 | if (this.minval > 0) this.minval = 0.99 * this.maxval; | ||
1566 | else this.minval = 1.01 * this.maxval; | ||
1567 | } | ||
1568 | |||
1569 | if (this.AlmostEqual2sComplement(this.minval, this.maxval, 4)) { | ||
1570 | if (this.maxval > 0) this.maxval *= 1.01; | ||
1571 | else this.maxval *= 0.99; | ||
1572 | if (this.AlmostEqual2sComplement(this.maxval, 0, 4)) this.maxval = 1.0; | ||
1573 | } | ||
1574 | return 0; | ||
1575 | }; | ||
1576 | |||
1577 | RrdGraph.prototype.leg_place = function (calc_width) | ||
1578 | { | ||
1579 | var interleg = this.TEXT.LEGEND.size * 1.5; | ||
1580 | var border = this.TEXT.LEGEND.size * 1.5; | ||
1581 | var fill = 0, fill_last; | ||
1582 | var legendwidth; // = this.ximg - 2 * border; | ||
1583 | var leg_c = 0; | ||
1584 | var leg_x = border; | ||
1585 | var leg_y = 0; //this.yimg; | ||
1586 | var leg_y_prev = 0; // this.yimg; | ||
1587 | var leg_cc; | ||
1588 | var glue = 0; | ||
1589 | var ii, mark = 0; | ||
1590 | var default_txtalign = RrdGraphDesc.TXA_JUSTIFIED; /*default line orientation */ | ||
1591 | var legspace; | ||
1592 | var tab; | ||
1593 | var saved_legend; | ||
1594 | |||
1595 | if(calc_width) legendwidth = 0; | ||
1596 | else legendwidth = this.legendwidth - 2 * border; | ||
1597 | |||
1598 | if (!this.no_legend && !this.only_graph) { | ||
1599 | legspace = []; | ||
1600 | for (var i = 0 , gdes_c = this.gdes.length; i < gdes_c; i++) { | ||
1601 | var prt_fctn; /*special printfunctions */ | ||
1602 | if(calc_width) saved_legend = this.gdes[i].legend; | ||
1603 | fill_last = fill; | ||
1604 | if (this.gdes[i].gf === RrdGraphDesc.GF_TEXTALIGN) | ||
1605 | default_txtalign = this.gdes[i].txtalign; | ||
1606 | |||
1607 | if (!this.force_rules_legend) { | ||
1608 | if (this.gdes[i].gf === RrdGraphDesc.GF_HRULE && (this.gdes[i].yrule < this.minval || this.gdes[i].yrule > this.maxval)) | ||
1609 | this.gdes[i].legend = null; | ||
1610 | if (this.gdes[i].gf === RrdGraphDesc.GF_VRULE && (this.gdes[i].xrule < this.start || this.gdes[i].xrule > this.end)) | ||
1611 | this.gdes[i].legend = null; | ||
1612 | } | ||
1613 | this.gdes[i].legend = this.gdes[i].legend.replace(/\\t/gi, "\t") /* turn \\t into tab */ | ||
1614 | |||
1615 | leg_cc = this.gdes[i].legend.length; | ||
1616 | /* is there a controle code at the end of the legend string ? */ | ||
1617 | if (leg_cc >= 2 && this.gdes[i].legend.charAt(leg_cc - 2) === '\\') { | ||
1618 | prt_fctn = this.gdes[i].legend.charAt(leg_cc - 1); | ||
1619 | leg_cc -= 2; | ||
1620 | this.gdes[i].legend = this.gdes[i].legend.substr(0,leg_cc); | ||
1621 | } else { | ||
1622 | prt_fctn = null; | ||
1623 | } | ||
1624 | /* only valid control codes */ | ||
1625 | if (prt_fctn != 'l' && prt_fctn != 'n' && prt_fctn != 'r' && prt_fctn != 'j' && prt_fctn != 'c' && | ||
1626 | prt_fctn != '.' && prt_fctn != 'u' && prt_fctn != 's' && prt_fctn != null && prt_fctn != 'g') { | ||
1627 | throw new RrdGraphError("Unknown control code at the end of "+this.gdes[i].legend+": "+prt_fctn); | ||
1628 | } | ||
1629 | /* \n -> \l */ | ||
1630 | if (prt_fctn === 'n') prt_fctn = 'l'; | ||
1631 | if (prt_fctn === '.') prt_fctn = '\0'; | ||
1632 | |||
1633 | /* remove exess space from the end of the legend for \g */ | ||
1634 | while (prt_fctn === 'g' && leg_cc > 0 && this.gdes[i].legend.charAt(leg_cc - 1) === ' ') { | ||
1635 | leg_cc--; | ||
1636 | this.gdes[i].legend = this.gdes[i].legend.substr(0,leg_cc); | ||
1637 | } | ||
1638 | |||
1639 | if (leg_cc != 0) { | ||
1640 | legspace[i] = (prt_fctn === 'g' ? 0 : interleg); | ||
1641 | if (fill > 0) fill += legspace[i]; | ||
1642 | fill += this.gfx.get_text_width(fill + border, this.TEXT.LEGEND, this.tabwidth, this.gdes[i].legend); | ||
1643 | leg_c++; | ||
1644 | } else { | ||
1645 | legspace[i] = 0; | ||
1646 | } | ||
1647 | /* who said there was a special tag ... ? */ | ||
1648 | if (prt_fctn === 'g') prt_fctn = null; | ||
1649 | |||
1650 | if (prt_fctn === null) { | ||
1651 | if(calc_width && (fill > legendwidth)) legendwidth = fill; | ||
1652 | |||
1653 | if (i === gdes_c - 1 || fill > legendwidth) { | ||
1654 | switch (default_txtalign) { | ||
1655 | case RrdGraphDesc.TXA_RIGHT: | ||
1656 | prt_fctn = 'r'; | ||
1657 | break; | ||
1658 | case RrdGraphDesc.TXA_CENTER: | ||
1659 | prt_fctn = 'c'; | ||
1660 | break; | ||
1661 | case RrdGraphDesc.TXA_JUSTIFIED: | ||
1662 | prt_fctn = 'j'; | ||
1663 | break; | ||
1664 | default: | ||
1665 | prt_fctn = 'l'; | ||
1666 | break; | ||
1667 | } | ||
1668 | } | ||
1669 | /* is it time to place the legends ? */ | ||
1670 | if (fill > legendwidth) { | ||
1671 | if (leg_c > 1) { /* go back one */ | ||
1672 | i--; | ||
1673 | fill = fill_last; | ||
1674 | leg_c--; | ||
1675 | } | ||
1676 | } | ||
1677 | if (leg_c === 1 && prt_fctn === 'j') { | ||
1678 | prt_fctn = 'l'; | ||
1679 | } | ||
1680 | } | ||
1681 | |||
1682 | if (prt_fctn != null) { | ||
1683 | leg_x = border; | ||
1684 | if (leg_c >= 2 && prt_fctn === 'j') { | ||
1685 | glue = (legendwidth - fill) / (leg_c - 1); | ||
1686 | } else { | ||
1687 | glue = 0; | ||
1688 | } | ||
1689 | if (prt_fctn === 'c') | ||
1690 | leg_x = border + (legendwidth - fill) / 2.0; | ||
1691 | if (prt_fctn === 'r') | ||
1692 | leg_x = legendwidth - fill + border; | ||
1693 | for (ii = mark; ii <= i; ii++) { | ||
1694 | if (this.gdes[ii].legend === '') continue; | ||
1695 | this.gdes[ii].leg_x = leg_x; | ||
1696 | this.gdes[ii].leg_y = leg_y + border; | ||
1697 | leg_x += this.gfx.get_text_width(leg_x, this.TEXT.LEGEND, this.tabwidth, this.gdes[ii].legend) + legspace[ii] + glue; | ||
1698 | } | ||
1699 | leg_y_prev = leg_y; | ||
1700 | if (leg_x > border || prt_fctn === 's') leg_y += this.TEXT.LEGEND.size * 1.4; | ||
1701 | if (prt_fctn === 's') leg_y -= this.TEXT.LEGEND.size; | ||
1702 | if (prt_fctn === 'u') leg_y -= this.TEXT.LEGEND.size * 1.4; | ||
1703 | |||
1704 | if(calc_width && (fill > legendwidth)) legendwidth = fill; | ||
1705 | fill = 0; | ||
1706 | leg_c = 0; | ||
1707 | mark = ii; | ||
1708 | } | ||
1709 | |||
1710 | if(calc_width) this.gdes[i].legend = saved_legend; | ||
1711 | } | ||
1712 | if(calc_width) this.legendwidth = legendwidth + 2 * border; | ||
1713 | else this.legendheight = leg_y + border * 0.6; // FIXME 0.6 ?? | ||
1714 | } | ||
1715 | return 0; | ||
1716 | }; | ||
1717 | |||
1718 | RrdGraph.prototype.axis_paint = function() | ||
1719 | { | ||
1720 | this.gfx.line(this.xorigin - 4, this.yorigin, | ||
1721 | this.xorigin + this.xsize + 4, this.yorigin, | ||
1722 | this.MGRIDWIDTH, this.GRC.AXIS); | ||
1723 | |||
1724 | this.gfx.line(this.xorigin, this.yorigin + 4, | ||
1725 | this.xorigin, this.yorigin - this.ysize - 4, | ||
1726 | this.MGRIDWIDTH, this.GRC.AXIS); | ||
1727 | |||
1728 | this.gfx.new_area(this.xorigin + this.xsize + 2, this.yorigin - 3, | ||
1729 | this.xorigin + this.xsize + 2, | ||
1730 | this.yorigin + 3, this.xorigin + this.xsize + 7, this.yorigin, | ||
1731 | this.GRC.ARROW); | ||
1732 | this.gfx.close_path(); | ||
1733 | |||
1734 | this.gfx.new_area(this.xorigin - 3, this.yorigin - this.ysize - 2, | ||
1735 | this.xorigin + 3, this.yorigin - this.ysize - 2, | ||
1736 | this.xorigin, this.yorigin - this.ysize - 7, | ||
1737 | this.GRC.ARROW); | ||
1738 | this.gfx.close_path(); | ||
1739 | |||
1740 | if (this.second_axis_scale != 0){ | ||
1741 | this.gfx.line (this.xorigin+this.xsize,this.yorigin+4, | ||
1742 | this.xorigin+this.xsize,this.yorigin-this.ysize-4, | ||
1743 | MGRIDWIDTH, this.graph_col[this.GRC.AXIS]); | ||
1744 | this.gfx.new_area (this.xorigin+this.xsize-2, this.yorigin-this.ysize-2, | ||
1745 | this.xorigin+this.xsize+3, this.yorigin-this.ysize-2, | ||
1746 | this.xorigin+this.xsize, this.yorigin-this.ysize-7, /* LINEOFFSET */ | ||
1747 | this.GRC.ARROW); | ||
1748 | this.gfx.close_path(); | ||
1749 | } | ||
1750 | }; | ||
1751 | |||
1752 | RrdGraph.prototype.frexp10 = function (x) | ||
1753 | { | ||
1754 | var mnt; | ||
1755 | var iexp; | ||
1756 | |||
1757 | iexp = Math.floor(Math.log(Math.abs(x)) / Math.LN10); | ||
1758 | mnt = x / Math.pow(10.0, iexp); | ||
1759 | if (mnt >= 10.0) { | ||
1760 | iexp++; | ||
1761 | mnt = x / Math.pow(10.0, iexp); | ||
1762 | } | ||
1763 | return [mnt, iexp]; | ||
1764 | }; | ||
1765 | |||
1766 | RrdGraph.prototype.horizontal_log_grid = function () | ||
1767 | { | ||
1768 | var yloglab = [ [ 1.0, 10., 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ], | ||
1769 | [ 1.0, 5.0, 10., 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ], | ||
1770 | [ 1.0, 2.0, 5.0, 7.0, 10., 0.0, 0.0, 0.0, 0.0, 0.0 ], | ||
1771 | [ 1.0, 2.0, 4.0, 6.0, 8.0, 10., 0.0, 0.0, 0.0, 0.0 ], | ||
1772 | [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10. ], | ||
1773 | [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] /* last line */ | ||
1774 | ]; | ||
1775 | var i, j, val_exp, min_exp; | ||
1776 | var nex; /* number of decades in data */ | ||
1777 | var logscale; /* scale in logarithmic space */ | ||
1778 | var exfrac = 1; /* decade spacing */ | ||
1779 | var mid = -1; /* row in yloglab for major grid */ | ||
1780 | var mspac; /* smallest major grid spacing (pixels) */ | ||
1781 | var flab; /* first value in yloglab to use */ | ||
1782 | var value, tmp, pre_value; | ||
1783 | var X0, X1, Y0; | ||
1784 | var graph_label; | ||
1785 | |||
1786 | nex = Math.log(this.maxval / this.minval)/Math.LN10; | ||
1787 | logscale = this.ysize / nex; | ||
1788 | /* major spacing for data with high dynamic range */ | ||
1789 | while (logscale * exfrac < 2.3 * this.TEXT.LEGEND.size) { // FIXME 3 -> 2.34 ?? | ||
1790 | if (exfrac === 1) exfrac = 2.3; // ??? 3 -> 2.34 | ||
1791 | else exfrac += 2.3 ; // 3-> 2.34 | ||
1792 | } | ||
1793 | /* major spacing for less dynamic data */ | ||
1794 | do { | ||
1795 | mid++; | ||
1796 | for (i = 0; yloglab[mid][i + 1] < 10.0; i++) {}; | ||
1797 | mspac = logscale * Math.log(10.0 / yloglab[mid][i])/Math.LN10; | ||
1798 | } while (mspac > 1.56 * this.TEXT.LEGEND.size && yloglab[mid][0] > 0); // FIXME 2->1.56 ?? | ||
1799 | if (mid) mid--; | ||
1800 | /* find first value in yloglab */ | ||
1801 | //for (flab = 0; yloglab[mid][flab] < 10 && this.frexp10(this.minval,tmp) > yloglab[mid][flab]; flab++); | ||
1802 | flab = -1; | ||
1803 | do { | ||
1804 | var ret; | ||
1805 | flab++; | ||
1806 | // [ret, tmp] = this.frexp10(this.minval); | ||
1807 | var dummy = this.frexp10(this.minval); ret = dummy[0]; tmp = dummy[1]; | ||
1808 | } while (yloglab[mid][flab] < 10 && ret > yloglab[mid][flab]); | ||
1809 | |||
1810 | if (yloglab[mid][flab] === 10.0) { | ||
1811 | tmp += 1.0; | ||
1812 | flab = 0; | ||
1813 | } | ||
1814 | |||
1815 | val_exp = tmp; | ||
1816 | if (val_exp % exfrac) val_exp += Math.abs(-val_exp % exfrac); | ||
1817 | X0 = this.xorigin; | ||
1818 | X1 = this.xorigin + this.xsize; | ||
1819 | |||
1820 | /* draw grid */ | ||
1821 | pre_value = Number.NAN; | ||
1822 | |||
1823 | while (1) { | ||
1824 | value = yloglab[mid][flab] * Math.pow(10.0, val_exp); | ||
1825 | if (this.AlmostEqual2sComplement(value, pre_value, 4)) // FIXME | ||
1826 | break; /* it seems we are not converging */ | ||
1827 | pre_value = value; | ||
1828 | Y0 = this.ytr(value); | ||
1829 | if (Math.floor(Y0 + 0.5) <= this.yorigin - this.ysize) | ||
1830 | break; | ||
1831 | /* major grid line */ | ||
1832 | this.gfx.line(X0 - 2, Y0, X0, Y0, this.MGRIDWIDTH, this.GRC.MGRID); | ||
1833 | this.gfx.line(X1, Y0, X1 + 2, Y0, this.MGRIDWIDTH, this.GRC.MGRID); | ||
1834 | this.gfx.dashed_line(X0 - 2, Y0, X1 + 2, Y0, this.MGRIDWIDTH, this.GRC.MGRID, this.grid_dash_on, this.grid_dash_off); | ||
1835 | /* label */ | ||
1836 | if (this.force_units_si) { | ||
1837 | var scale; | ||
1838 | var pvalue; | ||
1839 | var symbol; | ||
1840 | |||
1841 | scale = Math.floor(val_exp / 3.0); | ||
1842 | if (value >= 1.0) pvalue = Math.pow(10.0, val_exp % 3); | ||
1843 | else pvalue = Math.pow(10.0, ((val_exp + 1) % 3) + 2); | ||
1844 | pvalue *= yloglab[mid][flab]; | ||
1845 | |||
1846 | if (((scale + this.si_symbcenter) < this.si_symbol.length) && ((scale + this.si_symbcenter) >= 0)) | ||
1847 | symbol = this.si_symbol[scale + this.si_symbcenter]; | ||
1848 | else | ||
1849 | symbol = '?'; | ||
1850 | graph_label = sprintf("%3.0f %s", pvalue, symbol); | ||
1851 | } else { | ||
1852 | graph_label = sprintf("%3.0e", value); | ||
1853 | } | ||
1854 | if (this.second_axis_scale != 0){ | ||
1855 | var graph_label_right; | ||
1856 | var sval = value*this.second_axis_scale+this.second_axis_shift; | ||
1857 | if (!this.second_axis_format[0]){ | ||
1858 | if (this.force_units_si) { | ||
1859 | var mfac = 1; | ||
1860 | var symb = ''; | ||
1861 | //[sval, symb, mfac ] = this.auto_scale(sval, symb, mfac); | ||
1862 | var dummy = this.auto_scale(sval, symb, mfac); sval = dummy[0]; symb = dummy[1]; mfac = dummy[2]; | ||
1863 | graph_label_right = sprintf("%4.0f %s", sval,symb); | ||
1864 | } else { | ||
1865 | graph_label_right = sprintf("%3.0e", sval); | ||
1866 | } | ||
1867 | } else { | ||
1868 | graph_label_right = sprintf(this.second_axis_format,sval,""); | ||
1869 | } | ||
1870 | this.gfx.text( X1+7, Y0, this.GRC.FONT, this.TEXT.AXIS, this.tabwidth,0.0, RrdGraph.GFX_H_LEFT, RrdGraph.GFX_V_CENTER, graph_label_right ); | ||
1871 | } | ||
1872 | |||
1873 | this.gfx.text(X0 - this.TEXT.AXIS.size, Y0, this.GRC.FONT, this.TEXT.AXIS, this.tabwidth, 0.0, RrdGraph.GFX_H_RIGHT, RrdGraph.GFX_V_CENTER, graph_label); | ||
1874 | if (mid < 4 && exfrac === 1) { /* minor grid */ | ||
1875 | if (flab === 0) { /* find first and last minor line behind current major line * i is the first line and j tha last */ | ||
1876 | min_exp = val_exp - 1; | ||
1877 | for (i = 1; yloglab[mid][i] < 10.0; i++) {}; | ||
1878 | i = yloglab[mid][i - 1] + 1; | ||
1879 | j = 10; | ||
1880 | } else { | ||
1881 | min_exp = val_exp; | ||
1882 | i = yloglab[mid][flab - 1] + 1; | ||
1883 | j = yloglab[mid][flab]; | ||
1884 | } | ||
1885 | for (; i < j; i++) { /* draw minor lines below current major line */ | ||
1886 | value = i * Math.pow(10.0, min_exp); | ||
1887 | if (value < this.minval) continue; | ||
1888 | Y0 = this.ytr(value); | ||
1889 | if (Math.floor(Y0 + 0.5) <= this.yorigin - this.ysize) break; | ||
1890 | this.gfx.line(X0 - 2, Y0, X0, Y0, this.GRIDWIDTH, this.GRC.GRID); | ||
1891 | this.gfx.line(X1, Y0, X1 + 2, Y0, this.GRIDWIDTH, this.GRC.GRID); | ||
1892 | this.gfx.dashed_line(X0 - 1, Y0, X1 + 1, Y0, this.GRIDWIDTH, this.GRC.GRID, this.grid_dash_on, this.grid_dash_off); | ||
1893 | } | ||
1894 | } else if (exfrac > 1) { | ||
1895 | for (i = val_exp - exfrac / 3 * 2; i < val_exp; i += exfrac / 3) { | ||
1896 | value = Math.pow(10.0, i); | ||
1897 | if (value < this.minval) continue; | ||
1898 | Y0 = this.ytr(value); | ||
1899 | if (Math.floor(Y0 + 0.5) <= this.yorigin - this.ysize) break; | ||
1900 | this.gfx.line(X0 - 2, Y0, X0, Y0, this.GRIDWIDTH, this.GRC.GRID); | ||
1901 | this.gfx.line(X1, Y0, X1 + 2, Y0, this.GRIDWIDTH, this.GRC.GRID); | ||
1902 | this.gfx.dashed_line(X0 - 1, Y0, X1 + 1, Y0, this.GRIDWIDTH, this.GRC.GRID, this.grid_dash_on, this.grid_dash_off); | ||
1903 | } | ||
1904 | } | ||
1905 | if (yloglab[mid][++flab] === 10.0) { /* next decade */ | ||
1906 | flab = 0; | ||
1907 | val_exp += exfrac; | ||
1908 | } | ||
1909 | } | ||
1910 | if (mid < 4 && exfrac === 1) { /* draw minor lines after highest major line */ | ||
1911 | if (flab === 0) { /* find first and last minor line below current major line * i is the first line and j tha last */ | ||
1912 | min_exp = val_exp - 1; | ||
1913 | for (i = 1; yloglab[mid][i] < 10.0; i++) {}; | ||
1914 | i = yloglab[mid][i - 1] + 1; | ||
1915 | j = 10; | ||
1916 | } else { | ||
1917 | min_exp = val_exp; | ||
1918 | i = yloglab[mid][flab - 1] + 1; | ||
1919 | j = yloglab[mid][flab]; | ||
1920 | } | ||
1921 | for (; i < j; i++) { /* draw minor lines below current major line */ | ||
1922 | value = i * Math.pow(10.0, min_exp); | ||
1923 | if (value < this.minval) continue; | ||
1924 | Y0 = this.ytr(value); | ||
1925 | if (Math.floor(Y0 + 0.5) <= this.yorigin - this.ysize) break; | ||
1926 | this.gfx.line(X0 - 2, Y0, X0, Y0, this.GRIDWIDTH, this.GRC.GRID); | ||
1927 | this.gfx.line(X1, Y0, X1 + 2, Y0, this.GRIDWIDTH, this.GRC.GRID); | ||
1928 | this.gfx.dashed_line(X0 - 1, Y0, X1 + 1, Y0, this.GRIDWIDTH, this.GRC.GRID, this.grid_dash_on, this.grid_dash_off); | ||
1929 | } | ||
1930 | } else if (exfrac > 1) { /* fancy minor gridlines */ | ||
1931 | for (i = val_exp - exfrac / 3 * 2; i < val_exp; i += exfrac / 3) { | ||
1932 | value = Math.pow(10.0, i); | ||
1933 | if (value < this.minval) continue; | ||
1934 | Y0 = this.ytr(value); | ||
1935 | if (Math.floor(Y0 + 0.5) <= this.yorigin - this.ysize) break; | ||
1936 | this.gfx.line(X0 - 2, Y0, X0, Y0, this.GRIDWIDTH, this.GRC.GRID); | ||
1937 | this.gfx.line(X1, Y0, X1 + 2, Y0, this.GRIDWIDTH, this.GRC.GRID); | ||
1938 | this.gfx.dashed_line(X0 - 1, Y0, X1 + 1, Y0, this.GRIDWIDTH, this.GRC.GRID, this.grid_dash_on, this.grid_dash_off); | ||
1939 | } | ||
1940 | } | ||
1941 | return 1; | ||
1942 | }; | ||
1943 | |||
1944 | RrdGraph.prototype.vertical_grid = function() | ||
1945 | { | ||
1946 | var xlab_sel; /* which sort of label and grid ? */ | ||
1947 | var ti, tilab, timajor; | ||
1948 | var factor; | ||
1949 | var graph_label; | ||
1950 | var X0, Y0, Y1; /* points for filled graph and more */ | ||
1951 | |||
1952 | /* the type of time grid is determined by finding the number of seconds per pixel in the graph */ | ||
1953 | if (this.xlab_user.minsec === -1) { | ||
1954 | factor = (this.end - this.start) / this.xsize; | ||
1955 | xlab_sel = 0; | ||
1956 | |||
1957 | while (this.xlab[xlab_sel + 1].minsec != -1 && this.xlab[xlab_sel + 1].minsec <= factor) xlab_sel++; | ||
1958 | if (xlab_sel === 0) xlab_sel=1; // FIXME XXX XXX xlab_sel == 0 ??? | ||
1959 | while (this.xlab[xlab_sel - 1].minsec === this.xlab[xlab_sel].minsec && this.xlab[xlab_sel].length > (this.end - this.start)) xlab_sel--; | ||
1960 | this.xlab_user = this.xlab[xlab_sel]; | ||
1961 | |||
1962 | } | ||
1963 | Y0 = this.yorigin; | ||
1964 | Y1 = this.yorigin - this.ysize; | ||
1965 | |||
1966 | if (!(this.no_minor)) { | ||
1967 | for ( ti = this.find_first_time(this.start, this.xlab_user.gridtm, this.xlab_user.gridst), | ||
1968 | timajor = this.find_first_time(this.start, this.xlab_user.mgridtm, this.xlab_user.mgridst); | ||
1969 | ti < this.end && ti != -1; | ||
1970 | ti = this.find_next_time(ti, this.xlab_user.gridtm, this.xlab_user.gridst)) { | ||
1971 | if (ti < this.start || ti > this.end) continue; | ||
1972 | while (timajor < ti && timajor != -1) timajor = this.find_next_time(timajor, this.xlab_user.mgridtm, this.xlab_user.mgridst); | ||
1973 | if (timajor === -1) break; | ||
1974 | if (ti === timajor) continue; | ||
1975 | X0 = this.xtr(ti); | ||
1976 | this.gfx.line(X0, Y1 - 2, X0, Y1, this.GRIDWIDTH, this.GRC.GRID); | ||
1977 | this.gfx.line(X0, Y0, X0, Y0 + 2, this.GRIDWIDTH, this.GRC.GRID); | ||
1978 | this.gfx.dashed_line(X0, Y0 + 1, X0, Y1 - 1, this.GRIDWIDTH, this.GRC.GRID, this.grid_dash_on, this.grid_dash_off); | ||
1979 | } | ||
1980 | } | ||
1981 | |||
1982 | for ( ti = this.find_first_time(this.start, this.xlab_user.mgridtm, this.xlab_user.mgridst); | ||
1983 | ti < this.end && ti != -1; | ||
1984 | ti = this.find_next_time(ti, this.xlab_user.mgridtm, this.xlab_user.mgridst) | ||
1985 | ) { | ||
1986 | if (ti < this.start || ti > this.end) continue; | ||
1987 | X0 = this.xtr(ti); | ||
1988 | this.gfx.line(X0, Y1 - 2, X0, Y1, this.MGRIDWIDTH, this.GRC.MGRID); | ||
1989 | this.gfx.line(X0, Y0, X0, Y0 + 3, this.MGRIDWIDTH, this.GRC.MGRID); | ||
1990 | this.gfx.dashed_line(X0, Y0 + 3, X0, Y1 - 2, this.MGRIDWIDTH, | ||
1991 | this.GRC.MGRID, this.grid_dash_on, this.grid_dash_off); | ||
1992 | } | ||
1993 | |||
1994 | for ( ti = this.find_first_time(this.start - this.xlab_user.precis / 2, this.xlab_user.labtm, this.xlab_user.labst); | ||
1995 | (ti <= this.end - this.xlab_user.precis / 2) && ti != -1; | ||
1996 | ti = this.find_next_time(ti, this.xlab_user.labtm, this.xlab_user.labst) | ||
1997 | ) { | ||
1998 | tilab = ti + this.xlab_user.precis / 2; | ||
1999 | if (tilab < this.start || tilab > this.end) | ||
2000 | continue; | ||
2001 | //localtime_r(&tilab, &tm); FIXME | ||
2002 | //strftime(graph_label, 99, this.xlab_user.stst, &tm); | ||
2003 | graph_label = strftime(this.xlab_user.stst, tilab); | ||
2004 | this.gfx.text(this.xtr(tilab), Y0 + 3, this.GRC.FONT, | ||
2005 | this.TEXT.AXIS, this.tabwidth, 0.0, | ||
2006 | RrdGraph.GFX_H_CENTER, RrdGraph.GFX_V_TOP, graph_label); | ||
2007 | } | ||
2008 | }; | ||
2009 | |||
2010 | RrdGraph.prototype.auto_scale = function (value, symb_ptr, magfact) | ||
2011 | { | ||
2012 | var sindex; | ||
2013 | |||
2014 | if (value === 0.0 || isNaN(value)) { | ||
2015 | sindex = 0; | ||
2016 | magfact = 1.0; | ||
2017 | } else { | ||
2018 | sindex = Math.floor((Math.log(Math.abs(value))/Math.LN10) / (Math.log(this.base)/Math.LN10)); | ||
2019 | magfact = Math.pow(this.base, sindex); | ||
2020 | value /= magfact; | ||
2021 | } | ||
2022 | if (sindex <= this.si_symbcenter && sindex >= -this.si_symbcenter) { | ||
2023 | symb_ptr = this.si_symbol[sindex + this.si_symbcenter]; | ||
2024 | } else { | ||
2025 | symb_ptr = '?'; | ||
2026 | } | ||
2027 | return [value, symb_ptr, magfact]; | ||
2028 | }; | ||
2029 | |||
2030 | RrdGraph.prototype.si_unit = function() | ||
2031 | { | ||
2032 | var digits; | ||
2033 | var viewdigits = 0; | ||
2034 | |||
2035 | digits = Math.floor(Math.log(Math.max(Math.abs(this.minval), Math.abs(this.maxval))) / Math.log(this.base)); | ||
2036 | |||
2037 | if (this.unitsexponent != 9999) { | ||
2038 | /* unitsexponent = 9, 6, 3, 0, -3, -6, -9, etc */ | ||
2039 | viewdigits = Math.floor(this.unitsexponent / 3); | ||
2040 | } else { | ||
2041 | viewdigits = digits; | ||
2042 | } | ||
2043 | |||
2044 | this.magfact = Math.pow(this.base, digits); | ||
2045 | |||
2046 | this.viewfactor = this.magfact / Math.pow(this.base, viewdigits); | ||
2047 | |||
2048 | if (((viewdigits + this.si_symbcenter) < this.si_symbol.length) && ((viewdigits + this.si_symbcenter) >= 0)) | ||
2049 | this.symbol = this.si_symbol[viewdigits + this.si_symbcenter]; | ||
2050 | else | ||
2051 | this.symbol = '?'; | ||
2052 | }; | ||
2053 | |||
2054 | RrdGraph.prototype.expand_range = function () | ||
2055 | { | ||
2056 | var sensiblevalues = [ 1000.0, 900.0, 800.0, 750.0, 700.0, 600.0, 500.0, 400.0, 300.0, 250.0, 200.0, 125.0, 100.0, 90.0, 80.0, 75.0, 70.0, 60.0, 50.0, 40.0, 30.0, 25.0, 20.0, 10.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.5, 3.0, 2.5, 2.0, 1.8, 1.5, 1.2, 1.0, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0, -1 ]; | ||
2057 | var scaled_min, scaled_max; | ||
2058 | var adj; | ||
2059 | var i; | ||
2060 | |||
2061 | if (isNaN(this.ygridstep)) { | ||
2062 | if (this.alt_autoscale) { | ||
2063 | var delt, fact; | ||
2064 | |||
2065 | delt = this.maxval - this.minval; | ||
2066 | adj = delt * 0.1; | ||
2067 | fact = 2.0 * Math.pow(10.0, Math.floor(Math.log(Math.max(Math.abs(this.minval), Math.abs(this.maxval)) / this.magfact)/Math.LN10) - 2); | ||
2068 | if (delt < fact) adj = (fact - delt) * 0.55; | ||
2069 | this.minval -= adj; | ||
2070 | this.maxval += adj; | ||
2071 | } else if (this.alt_autoscale_min) { | ||
2072 | adj = (this.maxval - this.minval) * 0.1; | ||
2073 | this.minval -= adj; | ||
2074 | } else if (this.alt_autoscale_max) { | ||
2075 | adj = (this.maxval - this.minval) * 0.1; | ||
2076 | this.maxval += adj; | ||
2077 | } else { | ||
2078 | scaled_min = this.minval / this.magfact; | ||
2079 | scaled_max = this.maxval / this.magfact; | ||
2080 | |||
2081 | for (i = 1; sensiblevalues[i] > 0; i++) { | ||
2082 | if (sensiblevalues[i - 1] >= scaled_min && sensiblevalues[i] <= scaled_min) | ||
2083 | this.minval = sensiblevalues[i] * this.magfact; | ||
2084 | if (-sensiblevalues[i - 1] <= scaled_min && -sensiblevalues[i] >= scaled_min) | ||
2085 | this.minval = -sensiblevalues[i - 1] * this.magfact; | ||
2086 | if (sensiblevalues[i - 1] >= scaled_max && sensiblevalues[i] <= scaled_max) | ||
2087 | this.maxval = sensiblevalues[i - 1] * this.magfact; | ||
2088 | if (-sensiblevalues[i - 1] <= scaled_max && -sensiblevalues[i] >= scaled_max) | ||
2089 | this.maxval = -sensiblevalues[i] * this.magfact; | ||
2090 | } | ||
2091 | } | ||
2092 | } else { | ||
2093 | this.minval = this.ylabfact * this.ygridstep * Math.floor(this.minval / (this.ylabfact * this.ygridstep)); | ||
2094 | this.maxval = this.ylabfact * this.ygridstep * Math.ceil(this.maxval / (this.ylabfact * this.ygridstep)); | ||
2095 | } | ||
2096 | }; | ||
2097 | |||
2098 | RrdGraph.prototype.calc_horizontal_grid = function() | ||
2099 | { | ||
2100 | var range; | ||
2101 | var scaledrange; | ||
2102 | var pixel, i; | ||
2103 | var gridind = 0; | ||
2104 | var decimals, fractionals; | ||
2105 | |||
2106 | this.ygrid_scale.labfact = 2; | ||
2107 | range = this.maxval - this.minval; | ||
2108 | scaledrange = range / this.magfact; | ||
2109 | if (isNaN(scaledrange) || !isFinite(scaledrange)) { | ||
2110 | return false; | ||
2111 | } | ||
2112 | |||
2113 | pixel = 1; | ||
2114 | if (isNaN(this.ygridstep)) { | ||
2115 | if (this.alt_ygrid) { | ||
2116 | decimals = Math.ceil(Math.log(Math.max(Math.abs(this.maxval), Math.abs(this.minval)) * this.viewfactor / this.magfact)/Math.LN10); | ||
2117 | if (decimals <= 0) decimals = 1; | ||
2118 | this.ygrid_scale.gridstep = Math.pow(10, Math.floor(Math.log(range * this.viewfactor / this.magfact)/Math.LN10)) / this.viewfactor * this.magfact; | ||
2119 | if (this.ygrid_scale.gridstep === 0) this.ygrid_scale.gridstep = 0.1; | ||
2120 | if (range / this.ygrid_scale.gridstep < 5 && this.ygrid_scale.gridstep >= 30) | ||
2121 | this.ygrid_scale.gridstep /= 10; | ||
2122 | if (range / this.ygrid_scale.gridstep > 15) | ||
2123 | this.ygrid_scale.gridstep *= 10; | ||
2124 | if (range / this.ygrid_scale.gridstep > 5) { | ||
2125 | this.ygrid_scale.labfact = 1; | ||
2126 | if (range / this.ygrid_scale.gridstep > 8 || this.ygrid_scale.gridstep < 1.8 * this.TEXT.AXIS.size) // 1.8 | ||
2127 | this.ygrid_scale.labfact = 2; | ||
2128 | } else { | ||
2129 | this.ygrid_scale.gridstep /= 5; | ||
2130 | this.ygrid_scale.labfact = 5; | ||
2131 | } | ||
2132 | |||
2133 | fractionals = Math.floor(Math.log(this.ygrid_scale.gridstep * this.ygrid_scale.labfact * this.viewfactor / this.magfact)/Math.LN10); | ||
2134 | if (fractionals < 0) { /* small amplitude. */ | ||
2135 | var len = decimals - fractionals + 1; | ||
2136 | if (this.unitslength < len + 2) this.unitslength = len + 2; | ||
2137 | this.ygrid_scale.labfmt = sprintf("%%%d.%df%s", len, -fractionals, (this.symbol != ' ' ? " %s" : "")); | ||
2138 | } else { | ||
2139 | var len = decimals + 1; | ||
2140 | if (this.unitslength < len + 2) this.unitslength = len + 2; | ||
2141 | this.ygrid_scale.labfmt = sprintf("%%%d.0f%s", len, (this.symbol != ' ' ? " %s" : "")); | ||
2142 | } | ||
2143 | } else { /* classic rrd grid */ | ||
2144 | for (i = 0; this.ylab[i].grid > 0; i++) { | ||
2145 | pixel = this.ysize / (scaledrange / this.ylab[i].grid); | ||
2146 | gridind = i; | ||
2147 | if (pixel >= 5) break; | ||
2148 | } | ||
2149 | for (i = 0; i < 4; i++) { | ||
2150 | if (pixel * this.ylab[gridind].lfac[i] >= 1.8 * this.TEXT.AXIS.size) { // 1.8 | ||
2151 | this.ygrid_scale.labfact = this.ylab[gridind].lfac[i]; | ||
2152 | break; | ||
2153 | } | ||
2154 | } | ||
2155 | this.ygrid_scale.gridstep = this.ylab[gridind].grid * this.magfact; | ||
2156 | } | ||
2157 | } else { | ||
2158 | this.ygrid_scale.gridstep = this.ygridstep; | ||
2159 | this.ygrid_scale.labfact = this.ylabfact; | ||
2160 | } | ||
2161 | return true; | ||
2162 | }; | ||
2163 | |||
2164 | RrdGraph.prototype.draw_horizontal_grid = function() | ||
2165 | { | ||
2166 | var i; | ||
2167 | var scaledstep; | ||
2168 | var graph_label; | ||
2169 | var nlabels = 0; | ||
2170 | var X0 = this.xorigin; | ||
2171 | var X1 = this.xorigin + this.xsize; | ||
2172 | var sgrid = Math.round(this.minval / this.ygrid_scale.gridstep - 1); | ||
2173 | var egrid = Math.round(this.maxval / this.ygrid_scale.gridstep + 1); | ||
2174 | var MaxY; | ||
2175 | var second_axis_magfact = 0; | ||
2176 | var second_axis_symb = ''; | ||
2177 | var Y0, YN; | ||
2178 | var sisym; | ||
2179 | |||
2180 | scaledstep = this.ygrid_scale.gridstep / this.magfact * this.viewfactor; | ||
2181 | MaxY = scaledstep * egrid; | ||
2182 | for (i = sgrid; i <= egrid; i++) { | ||
2183 | Y0 = this.ytr(this.ygrid_scale.gridstep * i); | ||
2184 | YN = this.ytr(this.ygrid_scale.gridstep * (i + 1)); | ||
2185 | if (Math.floor(Y0 + 0.5) >= this.yorigin - this.ysize && Math.floor(Y0 + 0.5) <= this.yorigin) { | ||
2186 | if (i % this.ygrid_scale.labfact === 0 || (nlabels === 1 && (YN < this.yorigin - this.ysize || YN > this.yorigin))) { | ||
2187 | if (this.symbol === ' ') { | ||
2188 | if (this.alt_ygrid) { | ||
2189 | graph_label = sprintf(this.ygrid_scale.labfmt, scaledstep * i); // FIXME | ||
2190 | } else { | ||
2191 | if (MaxY < 10) { | ||
2192 | graph_label = sprintf("%4.1f", scaledstep * i); | ||
2193 | } else { | ||
2194 | graph_label = sprintf("%4.0f", scaledstep * i); | ||
2195 | } | ||
2196 | } | ||
2197 | } else { | ||
2198 | sisym = (i === 0 ? ' ' : this.symbol); | ||
2199 | if (this.alt_ygrid) { | ||
2200 | graph_label = sprintf(this.ygrid_scale.labfmt, scaledstep * i, sisym); | ||
2201 | } else { | ||
2202 | if (MaxY < 10) { | ||
2203 | graph_label = sprintf("%4.1f %s", scaledstep * i, sisym); | ||
2204 | } else { | ||
2205 | graph_label = sprintf("%4.0f %s", scaledstep * i, sisym); | ||
2206 | } | ||
2207 | } | ||
2208 | } | ||
2209 | nlabels++; | ||
2210 | if (this.second_axis_scale != 0){ | ||
2211 | var graph_label_right; | ||
2212 | sval = this.ygrid_scale.gridstep*i*this.second_axis_scale+this.second_axis_shift; | ||
2213 | if (!this.second_axis_format){ | ||
2214 | if (!second_axis_magfact){ | ||
2215 | var dummy = this.ygrid_scale.gridstep*(sgrid+egrid)/2.0*this.second_axis_scale+this.second_axis_shift; | ||
2216 | //[dummy, second_axis_symb, second_axis_magfact ] = this.auto_scale(dummy,second_axis_symb,second_axis_magfact); | ||
2217 | dummy = this.auto_scale(dummy,second_axis_symb,second_axis_magfact); second_axis_symb = dummy[1]; second_axis_magfact=dummy[2]; | ||
2218 | } | ||
2219 | sval /= second_axis_magfact; | ||
2220 | if(MaxY < 10) { | ||
2221 | graph_label_right = sprintf("%5.1f %s", sval, second_axis_symb); | ||
2222 | } else { | ||
2223 | graph_label_right = sprintf("%5.0f %s", sval, second_axis_symb); | ||
2224 | } | ||
2225 | } else { | ||
2226 | graph_label_right = sprintf(this.second_axis_format, sval); | ||
2227 | } | ||
2228 | this.gfx.text (X1+7, Y0, this.GRC.FONT, this.TEXT.AXIS, this.tabwidth, 0.0, RrdGraph.GFX_H_LEFT, RrdGraph.GFX_V_CENTER, graph_label_right ); | ||
2229 | } | ||
2230 | this.gfx.text(X0 - this.TEXT.AXIS.size , Y0, this.GRC.FONT, this.TEXT.AXIS , this.tabwidth, 0.0, RrdGraph.GFX_H_RIGHT, RrdGraph.GFX_V_CENTER, graph_label); | ||
2231 | this.gfx.line(X0 - 2, Y0, X0, Y0, this.MGRIDWIDTH, this.GRC.MGRID); | ||
2232 | this.gfx.line(X1, Y0, X1 + 2, Y0, this.MGRIDWIDTH, this.GRC.MGRID); | ||
2233 | this.gfx.dashed_line(X0 - 2, Y0, X1 + 2, Y0, this.MGRIDWIDTH, this.GRC.MGRID, this.grid_dash_on, this.grid_dash_off); | ||
2234 | } else if (!this.no_minor) { | ||
2235 | this.gfx.line( X0 - 2, Y0, X0, Y0, this.GRIDWIDTH, this.GRC.GRID); | ||
2236 | this.gfx.line(X1, Y0, X1 + 2, Y0, this.GRIDWIDTH, this.GRC.GRID); | ||
2237 | this.gfx.dashed_line(X0 - 1, Y0, X1 + 1, Y0, this.GRIDWIDTH, this.GRC.GRID, this.grid_dash_on, this.grid_dash_off); | ||
2238 | } | ||
2239 | } | ||
2240 | } | ||
2241 | return 1; | ||
2242 | }; | ||
2243 | |||
2244 | RrdGraph.prototype.grid_paint = function() | ||
2245 | { | ||
2246 | var i; | ||
2247 | var res = 0; | ||
2248 | var X0, Y0; | ||
2249 | |||
2250 | if (this.draw_3d_border > 0) { | ||
2251 | i = this.draw_3d_border; | ||
2252 | this.gfx.new_area(0, this.yimg, i, this.yimg - i, i, i, this.GRC.SHADEA); | ||
2253 | this.gfx.add_point(this.ximg - i, i); | ||
2254 | this.gfx.add_point(this.ximg, 0); | ||
2255 | this.gfx.add_point(0, 0); | ||
2256 | this.gfx.close_path(); | ||
2257 | this.gfx.new_area(i, this.yimg - i, this.ximg - i, this.yimg - i, this.ximg - i, i, this.GRC.SHADEB); | ||
2258 | this.gfx.add_point(this.ximg, 0); | ||
2259 | this.gfx.add_point(this.ximg, this.yimg); | ||
2260 | this.gfx.add_point(0, this.yimg); | ||
2261 | this.gfx.close_path(); | ||
2262 | } | ||
2263 | if (this.draw_x_grid) | ||
2264 | this.vertical_grid(); | ||
2265 | if (this.draw_y_grid) { | ||
2266 | if (this.logarithmic) | ||
2267 | res = this.horizontal_log_grid(); | ||
2268 | else | ||
2269 | res = this.draw_horizontal_grid(); | ||
2270 | /* dont draw horizontal grid if there is no min and max val */ | ||
2271 | if (!res) { | ||
2272 | this.gfx.text(this.ximg / 2, (2 * this.yorigin - this.ysize) / 2, | ||
2273 | this.GRC.FONT, this.TEXT.AXIS, | ||
2274 | this.tabwidth, 0.0, | ||
2275 | RrdGraph.GFX_H_CENTER, RrdGraph.GFX_V_CENTER, 'No Data found'); | ||
2276 | } | ||
2277 | } | ||
2278 | |||
2279 | /* yaxis unit description */ | ||
2280 | if (this.ylegend){ | ||
2281 | this.gfx.text(this.xOriginLegendY+10, this.yOriginLegendY, | ||
2282 | this.GRC.FONT, this.TEXT.UNIT, this.tabwidth, this.YLEGEND_ANGLE, | ||
2283 | RrdGraph.GFX_H_CENTER, RrdGraph.GFX_V_CENTER, this.ylegend); | ||
2284 | |||
2285 | } | ||
2286 | if (this.second_axis_legend){ | ||
2287 | this.gfx.text(this.xOriginLegendY2+10, this.yOriginLegendY2, | ||
2288 | this.GRC.FONT, this.TEXT.UNIT, this.tabwidth, this.YLEGEND_ANGLE, | ||
2289 | RrdGraph.GFX_H_CENTER, RrdGraph.GFX_V_CENTER, this.second_axis_legend); | ||
2290 | } | ||
2291 | |||
2292 | /* graph title */ | ||
2293 | this.gfx.text(this.xOriginTitle, this.yOriginTitle+6, | ||
2294 | this.GRC.FONT, this.TEXT.TITLE, this.tabwidth, 0.0, RrdGraph.GFX_H_CENTER, RrdGraph.GFX_V_TOP, this.title); | ||
2295 | /* rrdtool 'logo' */ | ||
2296 | if (!this.no_rrdtool_tag){ | ||
2297 | var color = this.parse_color(this.GRC.FONT); | ||
2298 | color[3] = 0.3; | ||
2299 | var water_color = this.color2rgba(color); | ||
2300 | var xpos = this.legendposition === RrdGraph.LEGEND_POS_EAST ? this.xOriginLegendY : this.ximg - 4; | ||
2301 | this.gfx.text(xpos, 5, water_color, this.TEXT.WATERMARK, this.tabwidth, | ||
2302 | -90, RrdGraph.GFX_H_LEFT, RrdGraph.GFX_V_TOP, "RRDTOOL / TOBI OETIKER"); | ||
2303 | } | ||
2304 | /* graph watermark */ | ||
2305 | if (this.watermark) { | ||
2306 | var color = this.parse_color(this.GRC.FONT) | ||
2307 | color[3] = 0.3; | ||
2308 | var water_color = this.color2rgba(color); | ||
2309 | this.gfx.text(this.ximg / 2, this.yimg - 6, water_color, this.TEXT.WATERMARK , this.tabwidth, 0, | ||
2310 | RrdGraph.GFX_H_CENTER, RrdGraph.GFX_V_BOTTOM, this.watermark); | ||
2311 | } | ||
2312 | /* graph labels */ | ||
2313 | if (!(this.no_legend) && !(this.only_graph)) { | ||
2314 | for (var i = 0 , gdes_c = this.gdes.length; i < gdes_c; i++) { | ||
2315 | if (!this.gdes[i].legend) continue; | ||
2316 | X0 = this.xOriginLegend + this.gdes[i].leg_x; | ||
2317 | Y0 = this.legenddirection === RrdGraph.LEGEND_DIR_TOP_DOWN ? this.yOriginLegend + this.gdes[i].leg_y : this.yOriginLegend + this.legendheight - this.gdes[i].leg_y; | ||
2318 | this.gfx.text(X0, Y0, this.GRC.FONT, this.TEXT.LEGEND, this.tabwidth, 0.0, RrdGraph.GFX_H_LEFT, RrdGraph.GFX_V_BOTTOM, this.gdes[i].legend); | ||
2319 | if (this.gdes[i].gf != RrdGraphDesc.GF_PRINT && this.gdes[i].gf != RrdGraphDesc.GF_GPRINT && this.gdes[i].gf != RrdGraphDesc.GF_COMMENT) { | ||
2320 | var boxH, boxV; | ||
2321 | var X1, Y1; | ||
2322 | |||
2323 | boxH = this.gfx.get_text_width(0,this.TEXT.LEGEND, this.tabwidth, 'o') * 1.2; | ||
2324 | boxV = boxH; | ||
2325 | |||
2326 | Y0 -= boxV * 0.4; | ||
2327 | |||
2328 | if (this.dynamic_labels && this.gdes[i].gf === RrdGraphDesc.GF_HRULE) { | ||
2329 | this.gfx.line(X0, Y0 - boxV / 2, X0 + boxH, Y0 - boxV / 2, 1.0, this.gdes[i].col); | ||
2330 | } else if (this.dynamic_labels && this.gdes[i].gf === RrdGraphDesc.GF_VRULE) { | ||
2331 | this.gfx.line(X0 + boxH / 2, Y0, X0 + boxH / 2, Y0 - boxV, 1.0, this.gdes[i].col); | ||
2332 | } else if (this.dynamic_labels && this.gdes[i].gf === RrdGraphDesc.GF_LINE) { | ||
2333 | this.gfx.line(X0, Y0, X0 + boxH, Y0 - boxV, this.gdes[i].linewidth, this.gdes[i].col); | ||
2334 | } else { | ||
2335 | this.gfx.new_area(X0, Y0 - boxV, X0, Y0, X0 + boxH, Y0, this.GRC.BACK); | ||
2336 | this.gfx.add_point(X0 + boxH, Y0 - boxV); | ||
2337 | this.gfx.close_path(); | ||
2338 | this.gfx.new_area(X0, Y0 - boxV, X0, Y0, X0 + boxH, Y0, this.gdes[i].col); | ||
2339 | this.gfx.add_point(X0 + boxH, Y0 - boxV); | ||
2340 | this.gfx.close_path(); | ||
2341 | if (this.gdes[i].dash) this.gfx.set_dash([ 3.0 ], 1, 0.0); | ||
2342 | this.gfx.rectangle(X0, Y0, X0 + boxH, Y0 - boxV, 1.0, this.GRC.FRAME); | ||
2343 | } | ||
2344 | } | ||
2345 | } | ||
2346 | } | ||
2347 | }; | ||
2348 | |||
2349 | RrdGraph.prototype.graph_size_location = function (elements) | ||
2350 | { | ||
2351 | var Xvertical = 0; | ||
2352 | var Xvertical2 = 0; | ||
2353 | var Ytitle = 0; | ||
2354 | var Xylabel = 0; | ||
2355 | var Xmain = 0; | ||
2356 | var Ymain = 0; | ||
2357 | var Yxlabel = 0; | ||
2358 | var Xspacing = 15; | ||
2359 | var Yspacing = 15; | ||
2360 | var Ywatermark = 4; | ||
2361 | |||
2362 | if (this.only_graph) { | ||
2363 | this.xorigin = 0; | ||
2364 | this.ximg = this.xsize; | ||
2365 | this.yimg = this.ysize; | ||
2366 | this.yorigin = this.ysize; | ||
2367 | this.xtr(0); | ||
2368 | this.ytr(Number.NaN); | ||
2369 | return 0; | ||
2370 | } | ||
2371 | |||
2372 | if(this.watermark) | ||
2373 | Ywatermark = this.TEXT.WATERMARK.size * 1.5; // 2 | ||
2374 | if(this.ylegend) | ||
2375 | Xvertical = this.TEXT.UNIT.size * 1.5; // 2 | ||
2376 | if(this.second_axis_legend) { | ||
2377 | Xvertical2 = this.TEXT.UNIT.size * 1.5; // 2 | ||
2378 | } else { | ||
2379 | Xvertical2 = Xspacing; | ||
2380 | } | ||
2381 | |||
2382 | if(this.title) | ||
2383 | Ytitle = this.TEXT.TITLE.size * 1.95 + 10; // 2.6 | ||
2384 | else | ||
2385 | Ytitle = Yspacing; | ||
2386 | |||
2387 | if (elements) { | ||
2388 | if (this.draw_x_grid) | ||
2389 | Yxlabel = this.TEXT.AXIS.size * 1.35; // 2.5 1.87 | ||
2390 | if (this.draw_y_grid || this.forceleftspace) // FIXME | ||
2391 | Xylabel = this.gfx.get_text_width(0, this.TEXT.AXIS, this.tabwidth, '0') * this.unitslength; | ||
2392 | } | ||
2393 | Xylabel += Xspacing; | ||
2394 | this.legendheight = 0; | ||
2395 | this.legendwidth = 0; | ||
2396 | if(!this.no_legend) { | ||
2397 | if(this.legendposition === RrdGraph.LEGEND_POS_WEST || this.legendposition === RrdGraph.LEGEND_POS_EAST){ | ||
2398 | if (this.leg_place(1) === -1) return -1; // FIXME | ||
2399 | } | ||
2400 | } | ||
2401 | |||
2402 | if(this.full_size_mode) { | ||
2403 | this.ximg = this.xsize; | ||
2404 | this.yimg = this.ysize; | ||
2405 | Xmain = this.ximg; | ||
2406 | Ymain = this.yimg; | ||
2407 | |||
2408 | Xmain -= Xylabel;// + Xspacing; | ||
2409 | if((this.legendposition === RrdGraph.LEGEND_POS_WEST || this.legendposition === RrdGraph.LEGEND_POS_EAST) && !(this.no_legend) ) | ||
2410 | Xmain -= this.legendwidth;// + Xspacing; | ||
2411 | if (this.second_axis_scale != 0) Xmain -= Xylabel; | ||
2412 | if (!(this.no_rrdtool_tag)) Xmain -= Xspacing; | ||
2413 | |||
2414 | Xmain -= Xvertical + Xvertical2; | ||
2415 | |||
2416 | if(Xmain < 1) Xmain = 1; | ||
2417 | this.xsize = Xmain; | ||
2418 | |||
2419 | if (!(this.no_legend)) { | ||
2420 | if(this.legendposition === RrdGraph.LEGEND_POS_NORTH || this.legendposition === RrdGraph.LEGEND_POS_SOUTH){ | ||
2421 | this.legendwidth = this.ximg; | ||
2422 | if (this.leg_place(0) === -1) return -1; | ||
2423 | } | ||
2424 | } | ||
2425 | |||
2426 | if( (this.legendposition === RrdGraph.LEGEND_POS_NORTH || this.legendposition === RrdGraph.LEGEND_POS_SOUTH) && !(this.no_legend) ) | ||
2427 | Ymain -= Yxlabel + this.legendheight; | ||
2428 | else Ymain -= Yxlabel; | ||
2429 | |||
2430 | Ymain -= Ytitle; | ||
2431 | |||
2432 | if (this.nolegened) Ymain -= 0.5*Yspacing; | ||
2433 | if (this.watermark) Ymain -= Ywatermark; | ||
2434 | if(Ymain < 1) Ymain = 1; | ||
2435 | this.ysize = Ymain; | ||
2436 | } else { | ||
2437 | if (elements) { | ||
2438 | // Xmain = this.xsize; // + Xspacing; | ||
2439 | Xmain = this.xsize + Xspacing; //FIXME ??? | ||
2440 | Ymain = this.ysize; | ||
2441 | } | ||
2442 | this.ximg = Xmain + Xylabel; | ||
2443 | if (!this.no_rrdtool_tag) this.ximg += Xspacing; | ||
2444 | |||
2445 | if( (this.legendposition === RrdGraph.LEGEND_POS_WEST || this.legendposition === RrdGraph.LEGEND_POS_EAST) && !this.no_legend ) | ||
2446 | this.ximg += this.legendwidth;// + Xspacing; | ||
2447 | if (this.second_axis_scale != 0) this.ximg += Xylabel; | ||
2448 | |||
2449 | this.ximg += Xvertical + Xvertical2; | ||
2450 | |||
2451 | if (!(this.no_legend)) { | ||
2452 | if(this.legendposition === RrdGraph.LEGEND_POS_NORTH || this.legendposition === RrdGraph.LEGEND_POS_SOUTH){ | ||
2453 | this.legendwidth = this.ximg; | ||
2454 | if (this.leg_place(0) === -1) return -1; | ||
2455 | } | ||
2456 | } | ||
2457 | |||
2458 | this.yimg = Ymain + Yxlabel; | ||
2459 | if( (this.legendposition === RrdGraph.LEGEND_POS_NORTH || this.legendposition === RrdGraph.LEGEND_POS_SOUTH) && !(this.no_legend) ) | ||
2460 | this.yimg += this.legendheight; | ||
2461 | |||
2462 | if (Ytitle) this.yimg += Ytitle; | ||
2463 | else this.yimg += 1.5 * Yspacing; | ||
2464 | |||
2465 | if (this.no_legend) this.yimg += 0.5*Yspacing; | ||
2466 | if (this.watermark) this.yimg += Ywatermark; | ||
2467 | } | ||
2468 | |||
2469 | |||
2470 | if (!this.no_legend) { | ||
2471 | if(this.legendposition === RrdGraph.LEGEND_POS_WEST || this.legendposition === RrdGraph.LEGEND_POS_EAST){ | ||
2472 | if (this.leg_place(0) === -1) return -1; | ||
2473 | } | ||
2474 | } | ||
2475 | |||
2476 | switch(this.legendposition){ | ||
2477 | case RrdGraph.LEGEND_POS_NORTH: | ||
2478 | this.xOriginTitle = Math.round(this.xsize / 2); | ||
2479 | this.yOriginTitle = 0; | ||
2480 | this.xOriginLegend = 0; | ||
2481 | this.yOriginLegend = Math.round(Ytitle); | ||
2482 | this.xOriginLegendY = 0; | ||
2483 | this.yOriginLegendY = Math.round(Ytitle + this.legendheight + (Ymain / 2) + Yxlabel); | ||
2484 | this.xorigin = Math.round(Xvertical + Xylabel); | ||
2485 | this.yorigin = Math.round(Ytitle + this.legendheight + Ymain); | ||
2486 | this.xOriginLegendY2 = Math.round(Xvertical + Xylabel + Xmain); | ||
2487 | if (this.second_axis_scale != 0) this.xOriginLegendY2 += Xylabel; | ||
2488 | this.yOriginLegendY2 = Math.round(Ytitle + this.legendheight + (Ymain / 2) + Yxlabel); | ||
2489 | break; | ||
2490 | case RrdGraph.LEGEND_POS_WEST: | ||
2491 | this.xOriginTitle = Math.round(this.legendwidth + this.xsize / 2); | ||
2492 | this.yOriginTitle = 0; | ||
2493 | this.xOriginLegend = 0; | ||
2494 | this.yOriginLegend = Math.round(Ytitle); | ||
2495 | this.xOriginLegendY = Math.round(this.legendwidth); | ||
2496 | this.yOriginLegendY = Math.round(Ytitle + (Ymain / 2)); | ||
2497 | this.xorigin = Math.round(this.legendwidth + Xvertical + Xylabel); | ||
2498 | this.yorigin = Math.round(Ytitle + Ymain); | ||
2499 | this.xOriginLegendY2 = Math.round(this.legendwidth + Xvertical + Xylabel + Xmain); | ||
2500 | if (this.second_axis_scale != 0) this.xOriginLegendY2 += Xylabel; | ||
2501 | this.yOriginLegendY2 = Math.round(Ytitle + (Ymain / 2)); | ||
2502 | break; | ||
2503 | case RrdGraph.LEGEND_POS_SOUTH: | ||
2504 | this.xOriginTitle = Math.round(this.xsize / 2); | ||
2505 | this.yOriginTitle = 0; | ||
2506 | this.xOriginLegend = 0; | ||
2507 | this.yOriginLegend = Math.round(Ytitle + Ymain + Yxlabel); | ||
2508 | this.xOriginLegendY = 0; | ||
2509 | this.yOriginLegendY = Math.round(Ytitle + (Ymain / 2)); | ||
2510 | this.xorigin = Math.round(Xvertical + Xylabel); | ||
2511 | this.yorigin = Math.round(Ytitle + Ymain); | ||
2512 | this.xOriginLegendY2 = Math.round(Xvertical + Xylabel + Xmain); | ||
2513 | if (this.second_axis_scale != 0) this.xOriginLegendY2 += Xylabel; | ||
2514 | this.yOriginLegendY2 = Math.round(Ytitle + (Ymain / 2)); | ||
2515 | break; | ||
2516 | case RrdGraph.LEGEND_POS_EAST: | ||
2517 | this.xOriginTitle = Math.round(this.xsize / 2); | ||
2518 | this.yOriginTitle = 0; | ||
2519 | this.xOriginLegend = Math.round(Xvertical + Xylabel + Xmain + Xvertical2); | ||
2520 | if (this.second_axis_scale != 0) this.xOriginLegend += Xylabel; | ||
2521 | this.yOriginLegend = Math.round(Ytitle); | ||
2522 | this.xOriginLegendY = 0; | ||
2523 | this.yOriginLegendY = Math.round(Ytitle + (Ymain / 2)); | ||
2524 | this.xorigin = Math.round(Xvertical + Xylabel); | ||
2525 | this.yorigin = Math.round(Ytitle + Ymain); | ||
2526 | this.xOriginLegendY2 = Math.round(Xvertical + Xylabel + Xmain); | ||
2527 | if (this.second_axis_scale != 0) this.xOriginLegendY2 += Xylabel; | ||
2528 | this.yOriginLegendY2 = Math.round(Ytitle + (Ymain / 2)); | ||
2529 | |||
2530 | if (!this.no_rrdtool_tag){ | ||
2531 | this.xOriginTitle += Xspacing; | ||
2532 | this.xOriginLegend += Xspacing; | ||
2533 | this.xOriginLegendY += Xspacing; | ||
2534 | this.xorigin += Xspacing; | ||
2535 | this.xOriginLegendY2 += Xspacing; | ||
2536 | } | ||
2537 | break; | ||
2538 | } | ||
2539 | this.xtr(0); | ||
2540 | this.ytr(Number.NaN); | ||
2541 | return 0; | ||
2542 | }; | ||
2543 | |||
2544 | RrdGraph.prototype.graph_paint = function() | ||
2545 | { | ||
2546 | if (this.logarithmic && this.minval <= 0) | ||
2547 | throw new RrdGraphError("for a logarithmic yaxis you must specify a lower-limit > 0"); | ||
2548 | |||
2549 | //var start_end = RrdTime.proc_start_end(this.start_t, this.end_t); | ||
2550 | //this.start = start_end[0]; | ||
2551 | //this.end = start_end[1]; | ||
2552 | |||
2553 | if (this.start < 3600 * 24 * 365 * 10) | ||
2554 | throw new RrdGraphError("the first entry to fetch should be after 1980 ("+this.start+")"); | ||
2555 | |||
2556 | if (this.end < this.start) | ||
2557 | throw new RrdGraphError("start ("+this.start+") should be less than end ("+this.end+")"); | ||
2558 | |||
2559 | //this.xlab_form = null | ||
2560 | this.xlab_user = { minsec: -1, length: 0, gridtm: 0, gridst: 0, mgridtm: 0, mgridst: 0, labtm: 0, labst: 0, precis: 0, stst: null }; | ||
2561 | this.ygrid_scale = { gridstep: 0.0, labfact:0 , labfmt: null }; | ||
2562 | this.minval = this.setminval; | ||
2563 | this.maxval = this.setmaxval; | ||
2564 | |||
2565 | this.step = Math.max(this.step, (this.end - this.start) / this.xsize); | ||
2566 | |||
2567 | for (var i = 0, gdes_c = this.gdes.length; i < gdes_c; i++) { | ||
2568 | this.gdes[i].step = 0; // FIXME 0? | ||
2569 | this.gdes[i].step_orig = this.step; | ||
2570 | this.gdes[i].start = this.start; // FIXME SHIFT | ||
2571 | // this.gdes[i].start_orig = this.start; | ||
2572 | this.gdes[i].end = this.end; // FIXME SHIFT | ||
2573 | // this.gdes[i].end_orig = this.end; | ||
2574 | } | ||
2575 | |||
2576 | var areazero = 0.0 | ||
2577 | var lastgdes = null; | ||
2578 | |||
2579 | if (this.data_fetch() === -1) | ||
2580 | return -1; | ||
2581 | if (this.data_calc() === -1) | ||
2582 | return -1; | ||
2583 | var i = this.print_calc(); | ||
2584 | if (i < 0) | ||
2585 | return -1; | ||
2586 | if (this.graph_size_location(i) === -1) | ||
2587 | return -1; | ||
2588 | |||
2589 | if (this.data_proc() === -1) | ||
2590 | return -1; | ||
2591 | if (!this.logarithmic) | ||
2592 | this.si_unit(); | ||
2593 | if (!this.rigid && !this.logarithmic) | ||
2594 | this.expand_range(); | ||
2595 | |||
2596 | if (this.magfact === 0) this.magfact =1; // FIXME logarithmic ¿? | ||
2597 | |||
2598 | if (!this.calc_horizontal_grid()) | ||
2599 | return -1; | ||
2600 | |||
2601 | this.ytr(Number.NaN); | ||
2602 | |||
2603 | this.gfx.size(this.ximg, this.yimg); | ||
2604 | |||
2605 | this.gfx.new_area(0, 0, 0, this.yimg, this.ximg, this.yimg, this.GRC.BACK); | ||
2606 | this.gfx.add_point(this.ximg, 0); | ||
2607 | this.gfx.close_path(); | ||
2608 | |||
2609 | this.gfx.new_area(this.xorigin, this.yorigin, this.xorigin + this.xsize, | ||
2610 | this.yorigin, this.xorigin + this.xsize, this.yorigin - this.ysize, this.GRC.CANVAS); | ||
2611 | this.gfx.add_point(this.xorigin, this.yorigin - this.ysize); | ||
2612 | this.gfx.close_path(); | ||
2613 | |||
2614 | //this.ctx.rect(this.xorigin, this.yorigin - this.ysize - 1.0, this.xsize, this.ysize + 2.0); | ||
2615 | //this.ctx.clip(); | ||
2616 | |||
2617 | if (this.minval > 0.0) areazero = this.minval; | ||
2618 | if (this.maxval < 0.0) areazero = this.maxval; | ||
2619 | |||
2620 | for (var i = 0, gdes_c = this.gdes.length; i < gdes_c; i++) { | ||
2621 | switch (this.gdes[i].gf) { | ||
2622 | case RrdGraphDesc.GF_CDEF: | ||
2623 | case RrdGraphDesc.GF_VDEF: | ||
2624 | case RrdGraphDesc.GF_DEF: | ||
2625 | case RrdGraphDesc.GF_PRINT: | ||
2626 | case RrdGraphDesc.GF_GPRINT: | ||
2627 | case RrdGraphDesc.GF_COMMENT: | ||
2628 | case RrdGraphDesc.GF_TEXTALIGN: | ||
2629 | case RrdGraphDesc.GF_HRULE: | ||
2630 | case RrdGraphDesc.GF_VRULE: | ||
2631 | case RrdGraphDesc.GF_XPORT: | ||
2632 | case RrdGraphDesc.GF_SHIFT: | ||
2633 | break; | ||
2634 | case RrdGraphDesc.GF_TICK: | ||
2635 | for (var ii = 0; ii < this.xsize; ii++) { | ||
2636 | if (!isNaN(this.gdes[i].p_data[ii]) && this.gdes[i].p_data[ii] != 0.0) { | ||
2637 | if (this.gdes[i].yrule > 0) { | ||
2638 | this.gfx.line(this.xorigin + ii, this.yorigin + 1.0, | ||
2639 | this.xorigin + ii, this.yorigin - this.gdes[i].yrule * this.ysize, 1.0, this.gdes[i].col); | ||
2640 | } else if (this.gdes[i].yrule < 0) { | ||
2641 | this.gfx.line(this.xorigin + ii, this.yorigin - this.ysize - 1.0, | ||
2642 | this.xorigin + ii, this.yorigin - this.ysize - this.gdes[i].yrule * this.ysize, 1.0, this.gdes[i].col); | ||
2643 | } | ||
2644 | } | ||
2645 | } | ||
2646 | break; | ||
2647 | case RrdGraphDesc.GF_LINE: | ||
2648 | case RrdGraphDesc.GF_AREA: | ||
2649 | var diffval = this.maxval - this.minval; | ||
2650 | var maxlimit = this.maxval + 9 * diffval; | ||
2651 | var minlimit = this.minval - 9 * diffval; | ||
2652 | for (var ii = 0; ii < this.xsize; ii++) { | ||
2653 | if (!isNaN(this.gdes[i].p_data[ii])) { // FIXME NaN < ??? | ||
2654 | if (!isFinite(this.gdes[i].p_data[ii])) { | ||
2655 | if (this.gdes[i].p_data[ii] > 0) this.gdes[i].p_data[ii] = this.maxval; | ||
2656 | else this.gdes[i].p_data[ii] = this.minval; | ||
2657 | } | ||
2658 | if (this.gdes[i].p_data[ii] > maxlimit) this.gdes[i].p_data[ii] = maxlimit; | ||
2659 | if (this.gdes[i].p_data[ii] < minlimit) this.gdes[i].p_data[ii] = minlimit; | ||
2660 | } | ||
2661 | } | ||
2662 | var color = this.parse_color(this.gdes[i].col); // if (this.gdes[i].col.alpha != 0.0) | ||
2663 | if (color[3] != 0.0) { | ||
2664 | if (this.gdes[i].gf === RrdGraphDesc.GF_LINE) { | ||
2665 | var last_y = 0.0; | ||
2666 | var draw_on = false; | ||
2667 | |||
2668 | if (this.gdes[i].dash) this.gfx.set_dash(this.gdes[i].p_dashes, this.gdes[i].ndash, this.gdes[i].offset); | ||
2669 | this.gfx.stroke_begin(this.gdes[i].linewidth, this.gdes[i].col); | ||
2670 | for (var ii = 1; ii < this.xsize; ii++) { | ||
2671 | if (isNaN(this.gdes[i].p_data[ii]) || (this.slopemode && isNaN(this.gdes[i].p_data[ii - 1]))) { | ||
2672 | draw_on = false; | ||
2673 | continue; | ||
2674 | } | ||
2675 | if (!draw_on) { | ||
2676 | last_y = this.ytr(this.gdes[i].p_data[ii]); | ||
2677 | if (!this.slopemode) { | ||
2678 | var x = ii - 1 + this.xorigin; | ||
2679 | var y = last_y; | ||
2680 | this.gfx.moveTo(x, y); | ||
2681 | x = ii + this.xorigin; | ||
2682 | y = last_y; | ||
2683 | this.gfx.lineTo(x, y) | ||
2684 | } else { | ||
2685 | var x = ii - 1 + this.xorigin; | ||
2686 | var y = this.ytr(this.gdes[i].p_data[ii - 1]); | ||
2687 | this.gfx.moveTo(x, y); | ||
2688 | x = ii + this.xorigin; | ||
2689 | y = last_y; | ||
2690 | this.gfx.lineTo(x, y); | ||
2691 | } | ||
2692 | draw_on = true; | ||
2693 | } else { | ||
2694 | var x1 = ii + this.xorigin; | ||
2695 | var y1 = this.ytr(this.gdes[i].p_data[ii]); | ||
2696 | |||
2697 | if (!this.slopemode && !this.AlmostEqual2sComplement(y1, last_y, 4)) { | ||
2698 | var x = ii - 1 + this.xorigin; | ||
2699 | var y = y1; | ||
2700 | |||
2701 | this.gfx.lineTo(x, y); | ||
2702 | } | ||
2703 | last_y = y1; | ||
2704 | this.gfx.lineTo(x1, y1); | ||
2705 | } | ||
2706 | } | ||
2707 | this.gfx.stroke_end(); | ||
2708 | } else { | ||
2709 | var idxI = -1; | ||
2710 | var foreY = []; | ||
2711 | var foreX = []; | ||
2712 | var backY = []; | ||
2713 | var backX = []; | ||
2714 | var drawem = false; | ||
2715 | |||
2716 | for (ii = 0; ii <= this.xsize; ii++) { | ||
2717 | var ybase, ytop; | ||
2718 | |||
2719 | if (idxI > 0 && (drawem || ii === this.xsize)) { | ||
2720 | var cntI = 1; | ||
2721 | var lastI = 0; | ||
2722 | |||
2723 | while (cntI < idxI && this.AlmostEqual2sComplement(foreY [lastI], foreY[cntI], 4) && | ||
2724 | this.AlmostEqual2sComplement(foreY [lastI], foreY [cntI + 1], 4)) cntI++; | ||
2725 | this.gfx.new_area(backX[0], backY[0], foreX[0], foreY[0], foreX[cntI], foreY[cntI], this.gdes[i].col); | ||
2726 | while (cntI < idxI) { | ||
2727 | lastI = cntI; | ||
2728 | cntI++; | ||
2729 | while (cntI < idxI && | ||
2730 | this.AlmostEqual2sComplement(foreY [lastI], foreY[cntI], 4) && | ||
2731 | this.AlmostEqual2sComplement(foreY [lastI], foreY [cntI + 1], 4)) cntI++; | ||
2732 | this.gfx.add_point(foreX[cntI], foreY[cntI]); | ||
2733 | } | ||
2734 | this.gfx.add_point(backX[idxI], backY[idxI]); | ||
2735 | while (idxI > 1) { | ||
2736 | lastI = idxI; | ||
2737 | idxI--; | ||
2738 | while (idxI > 1 && | ||
2739 | this.AlmostEqual2sComplement(backY [lastI], backY[idxI], 4) && | ||
2740 | this.AlmostEqual2sComplement(backY [lastI], backY [idxI - 1], 4)) idxI--; | ||
2741 | this.gfx.add_point(backX[idxI], backY[idxI]); | ||
2742 | } | ||
2743 | idxI = -1; | ||
2744 | drawem = false; | ||
2745 | this.gfx.close_path(); | ||
2746 | } | ||
2747 | if (drawem) { | ||
2748 | drawem = false; | ||
2749 | idxI = -1; | ||
2750 | } | ||
2751 | if (ii === this.xsize) | ||
2752 | break; | ||
2753 | if (!this.slopemode && ii === 0) | ||
2754 | continue; | ||
2755 | if (isNaN(this.gdes[i].p_data[ii])) { | ||
2756 | drawem = true; | ||
2757 | continue; | ||
2758 | } | ||
2759 | ytop = this.ytr(this.gdes[i].p_data[ii]); | ||
2760 | if (lastgdes && this.gdes[i].stack) ybase = this.ytr(lastgdes.p_data[ii]); | ||
2761 | else ybase = this.ytr(areazero); | ||
2762 | if (ybase === ytop) { | ||
2763 | drawem = true; | ||
2764 | continue; | ||
2765 | } | ||
2766 | if (ybase > ytop) { | ||
2767 | var extra = ytop; | ||
2768 | ytop = ybase; | ||
2769 | ybase = extra; | ||
2770 | } | ||
2771 | if (!this.slopemode) { | ||
2772 | backY[++idxI] = ybase - 0.2; | ||
2773 | backX[idxI] = ii + this.xorigin - 1; | ||
2774 | foreY[idxI] = ytop + 0.2; | ||
2775 | foreX[idxI] = ii + this.xorigin - 1; | ||
2776 | } | ||
2777 | backY[++idxI] = ybase - 0.2; | ||
2778 | backX[idxI] = ii + this.xorigin; | ||
2779 | foreY[idxI] = ytop + 0.2; | ||
2780 | foreX[idxI] = ii + this.xorigin; | ||
2781 | } | ||
2782 | } | ||
2783 | } | ||
2784 | /* if color != 0x0 */ | ||
2785 | /* make sure we do not run into trouble when stacking on NaN */ | ||
2786 | for (ii = 0; ii < this.xsize; ii++) { | ||
2787 | if (isNaN(this.gdes[i].p_data[ii])) { | ||
2788 | if (lastgdes && (this.gdes[i].stack)) this.gdes[i].p_data[ii] = lastgdes.p_data[ii]; | ||
2789 | else this.gdes[i].p_data[ii] = areazero; | ||
2790 | } | ||
2791 | } | ||
2792 | lastgdes = this.gdes[i]; //lastgdes = &(this.gdes[i]); | ||
2793 | break; | ||
2794 | case RrdGraphDesc.GF_STACK: | ||
2795 | throw new RrdGraphError("STACK should already be turned into LINE or AREA here"); | ||
2796 | break; | ||
2797 | } | ||
2798 | } | ||
2799 | //cairo_reset_clip(this.cr); | ||
2800 | if (!this.only_graph) | ||
2801 | this.grid_paint(); | ||
2802 | if (!this.only_graph) | ||
2803 | this.axis_paint(); | ||
2804 | /* the RULES are the last thing to paint ... */ | ||
2805 | for (var i = 0, gdes_c = this.gdes.length; i < gdes_c; i++) { | ||
2806 | switch (this.gdes[i].gf) { | ||
2807 | case RrdGraphDesc.GF_HRULE: | ||
2808 | if (this.gdes[i].yrule >= this.minval && this.gdes[i].yrule <= this.maxval) { | ||
2809 | if (this.gdes[i].dash) this.gfx.set_dash(this.gdes[i].p_dashes, this.gdes[i].ndash, this.gdes[i].offset); | ||
2810 | this.gfx.line(this.xorigin, this.ytr(this.gdes[i].yrule), | ||
2811 | this.xorigin + this.xsize, this.ytr(this.gdes[i].yrule), 1.0, this.gdes[i].col); | ||
2812 | } | ||
2813 | break; | ||
2814 | case RrdGraphDesc.GF_VRULE: | ||
2815 | if (this.gdes[i].xrule >= this.start && this.gdes[i].xrule <= this.end) { | ||
2816 | if (this.gdes[i].dash) this.gfx.set_dash(this.gdes[i].p_dashes, this.gdes[i].ndash, this.gdes[i].offset); | ||
2817 | this.gfx.line(this.xtr(this.gdes[i].xrule), this.yorigin, | ||
2818 | this.xtr(this.gdes[i].xrule), this.yorigin - this.ysize, 1.0, this.gdes[i].col); | ||
2819 | } | ||
2820 | break; | ||
2821 | default: | ||
2822 | break; | ||
2823 | } | ||
2824 | } | ||
2825 | return 0; | ||
2826 | }; | ||
2827 | |||
2828 | RrdGraph.prototype.find_var = function(key) | ||
2829 | { | ||
2830 | for (var ii = 0, gdes_c = this.gdes.length; ii < gdes_c; ii++) { | ||
2831 | if ((this.gdes[ii].gf === RrdGraphDesc.GF_DEF || | ||
2832 | this.gdes[ii].gf === RrdGraphDesc.GF_VDEF || | ||
2833 | this.gdes[ii].gf === RrdGraphDesc.GF_CDEF) | ||
2834 | && this.gdes[ii].vname === key) { | ||
2835 | return ii; | ||
2836 | } | ||
2837 | } | ||
2838 | return -1; | ||
2839 | }; | ||
2840 | |||
2841 | RrdGraph.prototype.gdes_add_def = function (vname, rrdfile, name, cf, step, start, end, reduce) | ||
2842 | { | ||
2843 | this.gdes.push(new RrdGraphDesc(this, RrdGraphDesc.GF_DEF, vname, rrdfile, name, cf, step, start, end, reduce)); | ||
2844 | }; | ||
2845 | |||
2846 | RrdGraph.prototype.gdes_add_cdef = function (vname, rpn) | ||
2847 | { | ||
2848 | this.gdes.push(new RrdGraphDesc(this, RrdGraphDesc.GF_CDEF, vname, rpn)); | ||
2849 | }; | ||
2850 | |||
2851 | RrdGraph.prototype.gdes_add_vdef = function (vname, rpn) | ||
2852 | { | ||
2853 | this.gdes.push(new RrdGraphDesc(this, RrdGraphDesc.GF_VDEF, vname, rpn)); | ||
2854 | }; | ||
2855 | |||
2856 | RrdGraph.prototype.gdes_add_shift = function (vname, offset) | ||
2857 | { | ||
2858 | this.gdes.push(new RrdGraphDesc(this, RrdGraphDesc.GF_SHIFT, vname, offset)); | ||
2859 | }; | ||
2860 | |||
2861 | RrdGraph.prototype.gdes_add_line = function (width, value, color, legend, stack) | ||
2862 | { | ||
2863 | this.gdes.push(new RrdGraphDesc(this, RrdGraphDesc.GF_LINE, width, value, color, legend, stack)); | ||
2864 | }; | ||
2865 | |||
2866 | RrdGraph.prototype.gdes_add_area = function (value, color, legend, stack) | ||
2867 | { | ||
2868 | this.gdes.push(new RrdGraphDesc(this, RrdGraphDesc.GF_AREA, value, color, legend, stack)); | ||
2869 | }; | ||
2870 | |||
2871 | RrdGraph.prototype.gdes_add_tick = function (vname, color, fraction, legend) | ||
2872 | { | ||
2873 | this.gdes.push(new RrdGraphDesc(this, RrdGraphDesc.GF_TICK, vname, color, fraction, legend)); | ||
2874 | }; | ||
2875 | |||
2876 | RrdGraph.prototype.gdes_add_gprint = function (vname, cf, format, strftimefmt) | ||
2877 | { | ||
2878 | this.gdes.push(new RrdGraphDesc(this, RrdGraphDesc.GF_GPRINT, vname, cf, format, strftimefmt)); | ||
2879 | }; | ||
2880 | |||
2881 | RrdGraph.prototype.gdes_add_comment = function (text) | ||
2882 | { | ||
2883 | this.gdes.push(new RrdGraphDesc(this, RrdGraphDesc.GF_COMMENT, text)); | ||
2884 | }; | ||
2885 | |||
2886 | RrdGraph.prototype.gdes_add_textalign = function (align) | ||
2887 | { | ||
2888 | this.gdes.push(new RrdGraphDesc(this, RrdGraphDesc.GF_TEXTALING, align)); | ||
2889 | }; | ||
2890 | |||
2891 | RrdGraph.prototype.gdes_add_vrule = function (time, color, legend) | ||
2892 | { | ||
2893 | this.gdes.push(new RrdGraphDesc(this, RrdGraphDesc.GF_VRULE, time, color, legend)); | ||
2894 | }; | ||
2895 | |||
2896 | RrdGraph.prototype.gdes_add_hrule = function (value, color, legend) | ||
2897 | { | ||
2898 | this.gdes.push(new RrdGraphDesc(this, RrdGraphDesc.GF_HRULE, value, color, legend)); | ||
2899 | }; | ||
2900 | |||
2901 | RrdGraph.prototype.tmt_conv = function (str) | ||
2902 | { | ||
2903 | switch (str) { | ||
2904 | case 'SECOND': return RrdGraph.TMT_SECOND; | ||
2905 | case 'MINUTE': return RrdGraph.TMT_MINUTE; | ||
2906 | case 'HOUR': return RrdGraph.TMT_HOUR; | ||
2907 | case 'DAY': return RrdGraph.TMT_DAY; | ||
2908 | case 'WEEK': return RrdGraph.TMT_WEEK; | ||
2909 | case 'MONTH': return RrdGraph.TMT_MONTH; | ||
2910 | case 'YEAR': return RrdGraph.TMT_YEAR; | ||
2911 | } | ||
2912 | return -1; | ||
2913 | }; | ||
2914 | |||