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 | |||
