[ Index ] |
PHP Cross Reference of vtigercrm-6.1.0 |
[Summary view] [Print] [Text view]
1 /** 2 * jqPlot 3 * Pure JavaScript plotting plugin using jQuery 4 * 5 * Version: 1.0.2 6 * Revision: 1108 7 * 8 * Copyright (c) 2009-2011 Chris Leonello 9 * jqPlot is currently available for use in all personal or commercial projects 10 * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL 11 * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can 12 * choose the license that best suits your project and use it accordingly. 13 * 14 * Although not required, the author would appreciate an email letting him 15 * know of any substantial use of jqPlot. You can reach the author at: 16 * chris at jqplot dot com or see http://www.jqplot.com/info.php . 17 * 18 * If you are feeling kind and generous, consider supporting the project by 19 * making a donation at: http://www.jqplot.com/donate.php . 20 * 21 * sprintf functions contained in jqplot.sprintf.js by Ash Searle: 22 * 23 * version 2007.04.27 24 * author Ash Searle 25 * http://hexmen.com/blog/2007/03/printf-sprintf/ 26 * http://hexmen.com/js/sprintf.js 27 * The author (Ash Searle) has placed this code in the public domain: 28 * "This code is unrestricted: you are free to use it however you like." 29 * 30 */ 31 (function($) { 32 /** 33 * Class: $.jqplot.MeterGaugeRenderer 34 * Plugin renderer to draw a meter gauge chart. 35 * 36 * Data consists of a single series with 1 data point to position the gauge needle. 37 * 38 * To use this renderer, you need to include the 39 * meter gauge renderer plugin, for example: 40 * 41 * > <script type="text/javascript" src="plugins/jqplot.meterGaugeRenderer.js"></script> 42 * 43 * Properties described here are passed into the $.jqplot function 44 * as options on the series renderer. For example: 45 * 46 * > plot0 = $.jqplot('chart0',[[18]],{ 47 * > title: 'Network Speed', 48 * > seriesDefaults: { 49 * > renderer: $.jqplot.MeterGaugeRenderer, 50 * > rendererOptions: { 51 * > label: 'MB/s' 52 * > } 53 * > } 54 * > }); 55 * 56 * A meterGauge plot does not support events. 57 */ 58 $.jqplot.MeterGaugeRenderer = function(){ 59 $.jqplot.LineRenderer.call(this); 60 }; 61 62 $.jqplot.MeterGaugeRenderer.prototype = new $.jqplot.LineRenderer(); 63 $.jqplot.MeterGaugeRenderer.prototype.constructor = $.jqplot.MeterGaugeRenderer; 64 65 // called with scope of a series 66 $.jqplot.MeterGaugeRenderer.prototype.init = function(options) { 67 // Group: Properties 68 // 69 // prop: diameter 70 // Outer diameter of the meterGauge, auto computed by default 71 this.diameter = null; 72 // prop: padding 73 // padding between the meterGauge and plot edges, auto 74 // calculated by default. 75 this.padding = null; 76 // prop: shadowOffset 77 // offset of the shadow from the gauge ring and offset of 78 // each succesive stroke of the shadow from the last. 79 this.shadowOffset = 2; 80 // prop: shadowAlpha 81 // transparency of the shadow (0 = transparent, 1 = opaque) 82 this.shadowAlpha = 0.07; 83 // prop: shadowDepth 84 // number of strokes to apply to the shadow, 85 // each stroke offset shadowOffset from the last. 86 this.shadowDepth = 4; 87 // prop: background 88 // background color of the inside of the gauge. 89 this.background = "#efefef"; 90 // prop: ringColor 91 // color of the outer ring, hub, and needle of the gauge. 92 this.ringColor = "#BBC6D0"; 93 // needle color not implemented yet. 94 this.needleColor = "#C3D3E5"; 95 // prop: tickColor 96 // color of the tick marks around the gauge. 97 this.tickColor = "989898"; 98 // prop: ringWidth 99 // width of the ring around the gauge. Auto computed by default. 100 this.ringWidth = null; 101 // prop: min 102 // Minimum value on the gauge. Auto computed by default 103 this.min; 104 // prop: max 105 // Maximum value on the gauge. Auto computed by default 106 this.max; 107 // prop: ticks 108 // Array of tick values. Auto computed by default. 109 this.ticks = []; 110 // prop: showTicks 111 // true to show ticks around gauge. 112 this.showTicks = true; 113 // prop: showTickLabels 114 // true to show tick labels next to ticks. 115 this.showTickLabels = true; 116 // prop: label 117 // A gauge label like 'kph' or 'Volts' 118 this.label = null; 119 // prop: labelHeightAdjust 120 // Number of Pixels to offset the label up (-) or down (+) from its default position. 121 this.labelHeightAdjust = 0; 122 // prop: labelPosition 123 // Where to position the label, either 'inside' or 'bottom'. 124 this.labelPosition = 'inside'; 125 // prop: intervals 126 // Array of ranges to be drawn around the gauge. 127 // Array of form: 128 // > [value1, value2, ...] 129 // indicating the values for the first, second, ... intervals. 130 this.intervals = []; 131 // prop: intervalColors 132 // Array of colors to use for the intervals. 133 this.intervalColors = [ "#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"]; 134 // prop: intervalInnerRadius 135 // Radius of the inner circle of the interval ring. 136 this.intervalInnerRadius = null; 137 // prop: intervalOuterRadius 138 // Radius of the outer circle of the interval ring. 139 this.intervalOuterRadius = null; 140 this.tickRenderer = $.jqplot.MeterGaugeTickRenderer; 141 // ticks spaced every 1, 2, 2.5, 5, 10, 20, .1, .2, .25, .5, etc. 142 this.tickPositions = [1, 2, 2.5, 5, 10]; 143 // prop: tickSpacing 144 // Degrees between ticks. This is a target number, if 145 // incompatible span and ticks are supplied, a suitable 146 // spacing close to this value will be computed. 147 this.tickSpacing = 30; 148 this.numberMinorTicks = null; 149 // prop: hubRadius 150 // Radius of the hub at the bottom center of gauge which the needle attaches to. 151 // Auto computed by default 152 this.hubRadius = null; 153 // prop: tickPadding 154 // padding of the tick marks to the outer ring and the tick labels to marks. 155 // Auto computed by default. 156 this.tickPadding = null; 157 // prop: needleThickness 158 // Maximum thickness the needle. Auto computed by default. 159 this.needleThickness = null; 160 // prop: needlePad 161 // Padding between needle and inner edge of the ring when the needle is at the min or max gauge value. 162 this.needlePad = 6; 163 // prop: pegNeedle 164 // True will stop needle just below/above the min/max values if data is below/above min/max, 165 // as if the meter is "pegged". 166 this.pegNeedle = true; 167 this._type = 'meterGauge'; 168 169 $.extend(true, this, options); 170 this.type = null; 171 this.numberTicks = null; 172 this.tickInterval = null; 173 // span, the sweep (in degrees) from min to max. This gauge is 174 // a semi-circle. 175 this.span = 180; 176 // get rid of this nonsense 177 // this.innerSpan = this.span; 178 if (this.type == 'circular') { 179 this.semiCircular = false; 180 } 181 else if (this.type != 'circular') { 182 this.semiCircular = true; 183 } 184 else { 185 this.semiCircular = (this.span <= 180) ? true : false; 186 } 187 this._tickPoints = []; 188 // reference to label element. 189 this._labelElem = null; 190 191 // start the gauge at the beginning of the span 192 this.startAngle = (90 + (360 - this.span)/2) * Math.PI/180; 193 this.endAngle = (90 - (360 - this.span)/2) * Math.PI/180; 194 195 this.setmin = !!(this.min == null); 196 this.setmax = !!(this.max == null); 197 198 // if given intervals and is an array of values, create labels and colors. 199 if (this.intervals.length) { 200 if (this.intervals[0].length == null || this.intervals.length == 1) { 201 for (var i=0; i<this.intervals.length; i++) { 202 this.intervals[i] = [this.intervals[i], this.intervals[i], this.intervalColors[i]]; 203 } 204 } 205 else if (this.intervals[0].length == 2) { 206 for (i=0; i<this.intervals.length; i++) { 207 this.intervals[i] = [this.intervals[i][0], this.intervals[i][1], this.intervalColors[i]]; 208 } 209 } 210 } 211 212 // compute min, max and ticks if not supplied: 213 if (this.ticks.length) { 214 if (this.ticks[0].length == null || this.ticks[0].length == 1) { 215 for (var i=0; i<this.ticks.length; i++) { 216 this.ticks[i] = [this.ticks[i], this.ticks[i]]; 217 } 218 } 219 this.min = (this.min == null) ? this.ticks[0][0] : this.min; 220 this.max = (this.max == null) ? this.ticks[this.ticks.length-1][0] : this.max; 221 this.setmin = false; 222 this.setmax = false; 223 this.numberTicks = this.ticks.length; 224 this.tickInterval = this.ticks[1][0] - this.ticks[0][0]; 225 this.tickFactor = Math.floor(parseFloat((Math.log(this.tickInterval)/Math.log(10)).toFixed(11))); 226 // use the first interal to calculate minor ticks; 227 this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor); 228 if (!this.numberMinorTicks) { 229 this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1); 230 } 231 if (!this.numberMinorTicks) { 232 this.numberMinorTicks = 1; 233 } 234 } 235 236 else if (this.intervals.length) { 237 this.min = (this.min == null) ? 0 : this.min; 238 this.setmin = false; 239 if (this.max == null) { 240 if (this.intervals[this.intervals.length-1][0] >= this.data[0][1]) { 241 this.max = this.intervals[this.intervals.length-1][0]; 242 this.setmax = false; 243 } 244 } 245 else { 246 this.setmax = false; 247 } 248 } 249 250 else { 251 // no ticks and no intervals supplied, put needle in middle 252 this.min = (this.min == null) ? 0 : this.min; 253 this.setmin = false; 254 if (this.max == null) { 255 this.max = this.data[0][1] * 1.25; 256 this.setmax = true; 257 } 258 else { 259 this.setmax = false; 260 } 261 } 262 }; 263 264 $.jqplot.MeterGaugeRenderer.prototype.setGridData = function(plot) { 265 // set gridData property. This will hold angle in radians of each data point. 266 var stack = []; 267 var td = []; 268 var sa = this.startAngle; 269 for (var i=0; i<this.data.length; i++){ 270 stack.push(this.data[i][1]); 271 td.push([this.data[i][0]]); 272 if (i>0) { 273 stack[i] += stack[i-1]; 274 } 275 } 276 var fact = Math.PI*2/stack[stack.length - 1]; 277 278 for (var i=0; i<stack.length; i++) { 279 td[i][1] = stack[i] * fact; 280 } 281 this.gridData = td; 282 }; 283 284 $.jqplot.MeterGaugeRenderer.prototype.makeGridData = function(data, plot) { 285 var stack = []; 286 var td = []; 287 var sa = this.startAngle; 288 for (var i=0; i<data.length; i++){ 289 stack.push(data[i][1]); 290 td.push([data[i][0]]); 291 if (i>0) { 292 stack[i] += stack[i-1]; 293 } 294 } 295 var fact = Math.PI*2/stack[stack.length - 1]; 296 297 for (var i=0; i<stack.length; i++) { 298 td[i][1] = stack[i] * fact; 299 } 300 return td; 301 }; 302 303 304 function getnmt(pos, interval, fact) { 305 var temp; 306 for (var i=pos.length-1; i>=0; i--) { 307 temp = interval/(pos[i] * Math.pow(10, fact)); 308 if (temp == 4 || temp == 5) { 309 return temp - 1; 310 } 311 } 312 return null; 313 } 314 315 // called with scope of series 316 $.jqplot.MeterGaugeRenderer.prototype.draw = function (ctx, gd, options) { 317 var i; 318 var opts = (options != undefined) ? options : {}; 319 // offset and direction of offset due to legend placement 320 var offx = 0; 321 var offy = 0; 322 var trans = 1; 323 if (options.legendInfo && options.legendInfo.placement == 'inside') { 324 var li = options.legendInfo; 325 switch (li.location) { 326 case 'nw': 327 offx = li.width + li.xoffset; 328 break; 329 case 'w': 330 offx = li.width + li.xoffset; 331 break; 332 case 'sw': 333 offx = li.width + li.xoffset; 334 break; 335 case 'ne': 336 offx = li.width + li.xoffset; 337 trans = -1; 338 break; 339 case 'e': 340 offx = li.width + li.xoffset; 341 trans = -1; 342 break; 343 case 'se': 344 offx = li.width + li.xoffset; 345 trans = -1; 346 break; 347 case 'n': 348 offy = li.height + li.yoffset; 349 break; 350 case 's': 351 offy = li.height + li.yoffset; 352 trans = -1; 353 break; 354 default: 355 break; 356 } 357 } 358 359 360 361 // pre-draw so can get it's dimensions. 362 if (this.label) { 363 this._labelElem = $('<div class="jqplot-meterGauge-label" style="position:absolute;">'+this.label+'</div>'); 364 this.canvas._elem.after(this._labelElem); 365 } 366 367 var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow; 368 var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine; 369 var fill = (opts.fill != undefined) ? opts.fill : this.fill; 370 var cw = ctx.canvas.width; 371 var ch = ctx.canvas.height; 372 if (this.padding == null) { 373 this.padding = Math.round(Math.min(cw, ch)/30); 374 } 375 var w = cw - offx - 2 * this.padding; 376 var h = ch - offy - 2 * this.padding; 377 if (this.labelPosition == 'bottom' && this.label) { 378 h -= this._labelElem.outerHeight(true); 379 } 380 var mindim = Math.min(w,h); 381 var d = mindim; 382 383 if (!this.diameter) { 384 if (this.semiCircular) { 385 if ( w >= 2*h) { 386 if (!this.ringWidth) { 387 this.ringWidth = 2*h/35; 388 } 389 this.needleThickness = this.needleThickness || 2+Math.pow(this.ringWidth, 0.8); 390 this.innerPad = this.ringWidth/2 + this.needleThickness/2 + this.needlePad; 391 this.diameter = 2 * (h - 2*this.innerPad); 392 } 393 else { 394 if (!this.ringWidth) { 395 this.ringWidth = w/35; 396 } 397 this.needleThickness = this.needleThickness || 2+Math.pow(this.ringWidth, 0.8); 398 this.innerPad = this.ringWidth/2 + this.needleThickness/2 + this.needlePad; 399 this.diameter = w - 2*this.innerPad - this.ringWidth - this.padding; 400 } 401 // center taking into account legend and over draw for gauge bottom below hub. 402 // this will be center of hub. 403 this._center = [(cw - trans * offx)/2 + trans * offx, (ch + trans*offy - this.padding - this.ringWidth - this.innerPad)]; 404 } 405 else { 406 if (!this.ringWidth) { 407 this.ringWidth = d/35; 408 } 409 this.needleThickness = this.needleThickness || 2+Math.pow(this.ringWidth, 0.8); 410 this.innerPad = 0; 411 this.diameter = d - this.ringWidth; 412 // center in middle of canvas taking into account legend. 413 // will be center of hub. 414 this._center = [(cw-trans*offx)/2 + trans * offx, (ch-trans*offy)/2 + trans * offy]; 415 } 416 } 417 418 419 if (this._labelElem && this.labelPosition == 'bottom') { 420 this._center[1] -= this._labelElem.outerHeight(true); 421 } 422 423 this._radius = this.diameter/2; 424 425 this.tickSpacing = 6000/this.diameter; 426 427 if (!this.hubRadius) { 428 this.hubRadius = this.diameter/18; 429 } 430 431 this.shadowOffset = 0.5 + this.ringWidth/9; 432 this.shadowWidth = this.ringWidth*1; 433 434 this.tickPadding = 3 + Math.pow(this.diameter/20, 0.7); 435 this.tickOuterRadius = this._radius - this.ringWidth/2 - this.tickPadding; 436 this.tickLength = (this.showTicks) ? this._radius/13 : 0; 437 438 if (this.ticks.length == 0) { 439 // no ticks, lets make some. 440 var max = this.max, 441 min = this.min, 442 setmax = this.setmax, 443 setmin = this.setmin, 444 ti = (max - min) * this.tickSpacing / this.span; 445 var tf = Math.floor(parseFloat((Math.log(ti)/Math.log(10)).toFixed(11))); 446 var tp = (ti/Math.pow(10, tf)); 447 (tp > 2 && tp <= 2.5) ? tp = 2.5 : tp = Math.ceil(tp); 448 var t = this.tickPositions; 449 var tpindex, nt; 450 451 for (i=0; i<t.length; i++) { 452 if (tp == t[i] || i && t[i-1] < tp && tp < t[i]) { 453 ti = t[i]*Math.pow(10, tf); 454 tpindex = i; 455 } 456 } 457 458 for (i=0; i<t.length; i++) { 459 if (tp == t[i] || i && t[i-1] < tp && tp < t[i]) { 460 ti = t[i]*Math.pow(10, tf); 461 nt = Math.ceil((max - min) / ti); 462 } 463 } 464 465 // both max and min are free 466 if (setmax && setmin) { 467 var tmin = (min > 0) ? min - min % ti : min - min % ti - ti; 468 if (!this.forceZero) { 469 var diff = Math.min(min - tmin, 0.8*ti); 470 var ntp = Math.floor(diff/t[tpindex]); 471 if (ntp > 1) { 472 tmin = tmin + t[tpindex] * (ntp-1); 473 if (parseInt(tmin, 10) != tmin && parseInt(tmin-t[tpindex], 10) == tmin-t[tpindex]) { 474 tmin = tmin - t[tpindex]; 475 } 476 } 477 } 478 if (min == tmin) { 479 min -= ti; 480 } 481 else { 482 // tmin should always be lower than dataMin 483 if (min - tmin > 0.23*ti) { 484 min = tmin; 485 } 486 else { 487 min = tmin -ti; 488 nt += 1; 489 } 490 } 491 nt += 1; 492 var tmax = min + (nt - 1) * ti; 493 if (max >= tmax) { 494 tmax += ti; 495 nt += 1; 496 } 497 // now tmax should always be mroe than dataMax 498 if (tmax - max < 0.23*ti) { 499 tmax += ti; 500 nt += 1; 501 } 502 this.max = max = tmax; 503 this.min = min; 504 505 this.tickInterval = ti; 506 this.numberTicks = nt; 507 var it; 508 for (i=0; i<nt; i++) { 509 it = parseFloat((min+i*ti).toFixed(11)); 510 this.ticks.push([it, it]); 511 } 512 this.max = this.ticks[nt-1][1]; 513 514 this.tickFactor = tf; 515 // determine number of minor ticks 516 517 this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor); 518 519 if (!this.numberMinorTicks) { 520 this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1); 521 } 522 } 523 // max is free, min is fixed 524 else if (setmax) { 525 var tmax = min + (nt - 1) * ti; 526 if (max >= tmax) { 527 max = tmax + ti; 528 nt += 1; 529 } 530 else { 531 max = tmax; 532 } 533 534 this.tickInterval = this.tickInterval || ti; 535 this.numberTicks = this.numberTicks || nt; 536 var it; 537 for (i=0; i<this.numberTicks; i++) { 538 it = parseFloat((min+i*this.tickInterval).toFixed(11)); 539 this.ticks.push([it, it]); 540 } 541 this.max = this.ticks[this.numberTicks-1][1]; 542 543 this.tickFactor = tf; 544 // determine number of minor ticks 545 this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor); 546 547 if (!this.numberMinorTicks) { 548 this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1); 549 } 550 } 551 552 // not setting max or min 553 if (!setmax && !setmin) { 554 var range = this.max - this.min; 555 tf = Math.floor(parseFloat((Math.log(range)/Math.log(10)).toFixed(11))) - 1; 556 var nticks = [5,6,4,7,3,8,9,10,2], res, numticks, nonSigDigits=0, sigRange; 557 // check to see how many zeros are at the end of the range 558 if (range > 1) { 559 var rstr = String(range); 560 if (rstr.search(/\./) == -1) { 561 var pos = rstr.search(/0+$/); 562 nonSigDigits = (pos > 0) ? rstr.length - pos - 1 : 0; 563 } 564 } 565 sigRange = range/Math.pow(10, nonSigDigits); 566 for (i=0; i<nticks.length; i++) { 567 res = sigRange/(nticks[i]-1); 568 if (res == parseInt(res, 10)) { 569 this.numberTicks = nticks[i]; 570 this.tickInterval = range/(this.numberTicks-1); 571 this.tickFactor = tf+1; 572 break; 573 } 574 } 575 var it; 576 for (i=0; i<this.numberTicks; i++) { 577 it = parseFloat((this.min+i*this.tickInterval).toFixed(11)); 578 this.ticks.push([it, it]); 579 } 580 // determine number of minor ticks 581 this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor); 582 583 if (!this.numberMinorTicks) { 584 this.numberMinorTicks = getnmt(this.tickPositions, this.tickInterval, this.tickFactor-1); 585 } 586 587 if (!this.numberMinorTicks) { 588 this.numberMinorTicks = 1; 589 var nums = [4, 5, 3, 6, 2]; 590 for (i=0; i<5; i++) { 591 var temp = this.tickInterval/nums[i]; 592 if (temp == parseInt(temp, 10)) { 593 this.numberMinorTicks = nums[i]-1; 594 break; 595 } 596 } 597 } 598 } 599 } 600 601 602 var r = this._radius, 603 sa = this.startAngle, 604 ea = this.endAngle, 605 pi = Math.PI, 606 hpi = Math.PI/2; 607 608 if (this.semiCircular) { 609 var overAngle = Math.atan(this.innerPad/r), 610 outersa = this.outerStartAngle = sa - overAngle, 611 outerea = this.outerEndAngle = ea + overAngle, 612 hubsa = this.hubStartAngle = sa - Math.atan(this.innerPad/this.hubRadius*2), 613 hubea = this.hubEndAngle = ea + Math.atan(this.innerPad/this.hubRadius*2); 614 615 ctx.save(); 616 617 ctx.translate(this._center[0], this._center[1]); 618 ctx.lineJoin = "round"; 619 ctx.lineCap = "round"; 620 621 // draw the innerbackground 622 ctx.save(); 623 ctx.beginPath(); 624 ctx.fillStyle = this.background; 625 ctx.arc(0, 0, r, outersa, outerea, false); 626 ctx.closePath(); 627 ctx.fill(); 628 ctx.restore(); 629 630 // draw the shadow 631 // the outer ring. 632 var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')'; 633 ctx.save(); 634 for (var i=0; i<this.shadowDepth; i++) { 635 ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI)); 636 ctx.beginPath(); 637 ctx.strokeStyle = shadowColor; 638 ctx.lineWidth = this.shadowWidth; 639 ctx.arc(0 ,0, r, outersa, outerea, false); 640 ctx.closePath(); 641 ctx.stroke(); 642 } 643 ctx.restore(); 644 645 // the inner hub. 646 ctx.save(); 647 var tempd = parseInt((this.shadowDepth+1)/2, 10); 648 for (var i=0; i<tempd; i++) { 649 ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI)); 650 ctx.beginPath(); 651 ctx.fillStyle = shadowColor; 652 ctx.arc(0 ,0, this.hubRadius, hubsa, hubea, false); 653 ctx.closePath(); 654 ctx.fill(); 655 } 656 ctx.restore(); 657 658 // draw the outer ring. 659 ctx.save(); 660 ctx.beginPath(); 661 ctx.strokeStyle = this.ringColor; 662 ctx.lineWidth = this.ringWidth; 663 ctx.arc(0 ,0, r, outersa, outerea, false); 664 ctx.closePath(); 665 ctx.stroke(); 666 ctx.restore(); 667 668 // draw the hub 669 670 ctx.save(); 671 ctx.beginPath(); 672 ctx.fillStyle = this.ringColor; 673 ctx.arc(0 ,0, this.hubRadius,hubsa, hubea, false); 674 ctx.closePath(); 675 ctx.fill(); 676 ctx.restore(); 677 678 // draw the ticks 679 if (this.showTicks) { 680 ctx.save(); 681 var orad = this.tickOuterRadius, 682 tl = this.tickLength, 683 mtl = tl/2, 684 nmt = this.numberMinorTicks, 685 ts = this.span * Math.PI / 180 / (this.ticks.length-1), 686 mts = ts/(nmt + 1); 687 688 for (i = 0; i<this.ticks.length; i++) { 689 ctx.beginPath(); 690 ctx.lineWidth = 1.5 + this.diameter/360; 691 ctx.strokeStyle = this.ringColor; 692 var wps = ts*i+sa; 693 ctx.moveTo(-orad * Math.cos(ts*i+sa), orad * Math.sin(ts*i+sa)); 694 ctx.lineTo(-(orad-tl) * Math.cos(ts*i+sa), (orad - tl) * Math.sin(ts*i+sa)); 695 this._tickPoints.push([(orad-tl) * Math.cos(ts*i+sa) + this._center[0] + this.canvas._offsets.left, (orad - tl) * Math.sin(ts*i+sa) + this._center[1] + this.canvas._offsets.top, ts*i+sa]); 696 ctx.stroke(); 697 ctx.lineWidth = 1.0 + this.diameter/440; 698 if (i<this.ticks.length-1) { 699 for (var j=1; j<=nmt; j++) { 700 ctx.beginPath(); 701 ctx.moveTo(-orad * Math.cos(ts*i+mts*j+sa), orad * Math.sin(ts*i+mts*j+sa)); 702 ctx.lineTo(-(orad-mtl) * Math.cos(ts*i+mts*j+sa), (orad-mtl) * Math.sin(ts*i+mts*j+sa)); 703 ctx.stroke(); 704 } 705 } 706 } 707 ctx.restore(); 708 } 709 710 // draw the tick labels 711 if (this.showTickLabels) { 712 var elem, l, t, ew, eh, dim, maxdim=0; 713 var tp = this.tickPadding * (1 - 1/(this.diameter/80+1)); 714 for (i=0; i<this.ticks.length; i++) { 715 elem = $('<div class="jqplot-meterGauge-tick" style="position:absolute;">'+this.ticks[i][1]+'</div>'); 716 this.canvas._elem.after(elem); 717 ew = elem.outerWidth(true); 718 eh = elem.outerHeight(true); 719 l = this._tickPoints[i][0] - ew * (this._tickPoints[i][2]-Math.PI)/Math.PI - tp * Math.cos(this._tickPoints[i][2]); 720 t = this._tickPoints[i][1] - eh/2 + eh/2 * Math.pow(Math.abs((Math.sin(this._tickPoints[i][2]))), 0.5) + tp/3 * Math.pow(Math.abs((Math.sin(this._tickPoints[i][2]))), 0.5) ; 721 // t = this._tickPoints[i][1] - eh/2 - eh/2 * Math.sin(this._tickPoints[i][2]) - tp/2 * Math.sin(this._tickPoints[i][2]); 722 elem.css({left:l, top:t}); 723 dim = ew*Math.cos(this._tickPoints[i][2]) + eh*Math.sin(Math.PI/2+this._tickPoints[i][2]/2); 724 maxdim = (dim > maxdim) ? dim : maxdim; 725 } 726 } 727 728 // draw the gauge label 729 if (this.label && this.labelPosition == 'inside') { 730 var l = this._center[0] + this.canvas._offsets.left; 731 var tp = this.tickPadding * (1 - 1/(this.diameter/80+1)); 732 var t = 0.5*(this._center[1] + this.canvas._offsets.top - this.hubRadius) + 0.5*(this._center[1] + this.canvas._offsets.top - this.tickOuterRadius + this.tickLength + tp) + this.labelHeightAdjust; 733 // this._labelElem = $('<div class="jqplot-meterGauge-label" style="position:absolute;">'+this.label+'</div>'); 734 // this.canvas._elem.after(this._labelElem); 735 l -= this._labelElem.outerWidth(true)/2; 736 t -= this._labelElem.outerHeight(true)/2; 737 this._labelElem.css({left:l, top:t}); 738 } 739 740 else if (this.label && this.labelPosition == 'bottom') { 741 var l = this._center[0] + this.canvas._offsets.left - this._labelElem.outerWidth(true)/2; 742 var t = this._center[1] + this.canvas._offsets.top + this.innerPad + + this.ringWidth + this.padding + this.labelHeightAdjust; 743 this._labelElem.css({left:l, top:t}); 744 745 } 746 747 // draw the intervals 748 749 ctx.save(); 750 var inner = this.intervalInnerRadius || this.hubRadius * 1.5; 751 if (this.intervalOuterRadius == null) { 752 if (this.showTickLabels) { 753 var outer = (this.tickOuterRadius - this.tickLength - this.tickPadding - this.diameter/8); 754 } 755 else { 756 var outer = (this.tickOuterRadius - this.tickLength - this.diameter/16); 757 } 758 } 759 else { 760 var outer = this.intervalOuterRadius; 761 } 762 var range = this.max - this.min; 763 var intrange = this.intervals[this.intervals.length-1] - this.min; 764 var start, end, span = this.span*Math.PI/180; 765 for (i=0; i<this.intervals.length; i++) { 766 start = (i == 0) ? sa : sa + (this.intervals[i-1][0] - this.min)*span/range; 767 if (start < 0) { 768 start = 0; 769 } 770 end = sa + (this.intervals[i][0] - this.min)*span/range; 771 if (end < 0) { 772 end = 0; 773 } 774 ctx.beginPath(); 775 ctx.fillStyle = this.intervals[i][2]; 776 ctx.arc(0, 0, inner, start, end, false); 777 ctx.lineTo(outer*Math.cos(end), outer*Math.sin(end)); 778 ctx.arc(0, 0, outer, end, start, true); 779 ctx.lineTo(inner*Math.cos(start), inner*Math.sin(start)); 780 ctx.closePath(); 781 ctx.fill(); 782 } 783 ctx.restore(); 784 785 // draw the needle 786 var datapoint = this.data[0][1]; 787 var dataspan = this.max - this.min; 788 if (this.pegNeedle) { 789 if (this.data[0][1] > this.max + dataspan*3/this.span) { 790 datapoint = this.max + dataspan*3/this.span; 791 } 792 if (this.data[0][1] < this.min - dataspan*3/this.span) { 793 datapoint = this.min - dataspan*3/this.span; 794 } 795 } 796 var dataang = (datapoint - this.min)/dataspan * this.span * Math.PI/180 + this.startAngle; 797 798 799 ctx.save(); 800 ctx.beginPath(); 801 ctx.fillStyle = this.ringColor; 802 ctx.strokeStyle = this.ringColor; 803 this.needleLength = (this.tickOuterRadius - this.tickLength) * 0.85; 804 this.needleThickness = (this.needleThickness < 2) ? 2 : this.needleThickness; 805 var endwidth = this.needleThickness * 0.4; 806 807 808 var dl = this.needleLength/10; 809 var dt = (this.needleThickness - endwidth)/10; 810 var templ; 811 for (var i=0; i<10; i++) { 812 templ = this.needleThickness - i*dt; 813 ctx.moveTo(dl*i*Math.cos(dataang), dl*i*Math.sin(dataang)); 814 ctx.lineWidth = templ; 815 ctx.lineTo(dl*(i+1)*Math.cos(dataang), dl*(i+1)*Math.sin(dataang)); 816 ctx.stroke(); 817 } 818 819 ctx.restore(); 820 } 821 else { 822 this._center = [(cw - trans * offx)/2 + trans * offx, (ch - trans*offy)/2 + trans * offy]; 823 } 824 }; 825 826 $.jqplot.MeterGaugeAxisRenderer = function() { 827 $.jqplot.LinearAxisRenderer.call(this); 828 }; 829 830 $.jqplot.MeterGaugeAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); 831 $.jqplot.MeterGaugeAxisRenderer.prototype.constructor = $.jqplot.MeterGaugeAxisRenderer; 832 833 834 // There are no traditional axes on a gauge chart. We just need to provide 835 // dummy objects with properties so the plot will render. 836 // called with scope of axis object. 837 $.jqplot.MeterGaugeAxisRenderer.prototype.init = function(options){ 838 // 839 this.tickRenderer = $.jqplot.MeterGaugeTickRenderer; 840 $.extend(true, this, options); 841 // I don't think I'm going to need _dataBounds here. 842 // have to go Axis scaling in a way to fit chart onto plot area 843 // and provide u2p and p2u functionality for mouse cursor, etc. 844 // for convienence set _dataBounds to 0 and 100 and 845 // set min/max to 0 and 100. 846 this._dataBounds = {min:0, max:100}; 847 this.min = 0; 848 this.max = 100; 849 this.showTicks = false; 850 this.ticks = []; 851 this.showMark = false; 852 this.show = false; 853 }; 854 855 $.jqplot.MeterGaugeLegendRenderer = function(){ 856 $.jqplot.TableLegendRenderer.call(this); 857 }; 858 859 $.jqplot.MeterGaugeLegendRenderer.prototype = new $.jqplot.TableLegendRenderer(); 860 $.jqplot.MeterGaugeLegendRenderer.prototype.constructor = $.jqplot.MeterGaugeLegendRenderer; 861 862 /** 863 * Class: $.jqplot.MeterGaugeLegendRenderer 864 *Meter gauges don't typically have a legend, this overrides the default legend renderer. 865 */ 866 $.jqplot.MeterGaugeLegendRenderer.prototype.init = function(options) { 867 // Maximum number of rows in the legend. 0 or null for unlimited. 868 this.numberRows = null; 869 // Maximum number of columns in the legend. 0 or null for unlimited. 870 this.numberColumns = null; 871 $.extend(true, this, options); 872 }; 873 874 // called with context of legend 875 $.jqplot.MeterGaugeLegendRenderer.prototype.draw = function() { 876 if (this.show) { 877 var series = this._series; 878 var ss = 'position:absolute;'; 879 ss += (this.background) ? 'background:'+this.background+';' : ''; 880 ss += (this.border) ? 'border:'+this.border+';' : ''; 881 ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : ''; 882 ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : ''; 883 ss += (this.textColor) ? 'color:'+this.textColor+';' : ''; 884 ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : ''; 885 ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : ''; 886 ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : ''; 887 ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : ''; 888 this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>'); 889 // MeterGauge charts legends don't go by number of series, but by number of data points 890 // in the series. Refactor things here for that. 891 892 var pad = false, 893 reverse = false, 894 nr, nc; 895 var s = series[0]; 896 897 if (s.show) { 898 var pd = s.data; 899 if (this.numberRows) { 900 nr = this.numberRows; 901 if (!this.numberColumns){ 902 nc = Math.ceil(pd.length/nr); 903 } 904 else{ 905 nc = this.numberColumns; 906 } 907 } 908 else if (this.numberColumns) { 909 nc = this.numberColumns; 910 nr = Math.ceil(pd.length/this.numberColumns); 911 } 912 else { 913 nr = pd.length; 914 nc = 1; 915 } 916 917 var i, j, tr, td1, td2, lt, rs, color; 918 var idx = 0; 919 920 for (i=0; i<nr; i++) { 921 if (reverse){ 922 tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem); 923 } 924 else{ 925 tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem); 926 } 927 for (j=0; j<nc; j++) { 928 if (idx < pd.length){ 929 // debugger 930 lt = this.labels[idx] || pd[idx][0].toString(); 931 color = s.color; 932 if (!reverse){ 933 if (i>0){ 934 pad = true; 935 } 936 else{ 937 pad = false; 938 } 939 } 940 else{ 941 if (i == nr -1){ 942 pad = false; 943 } 944 else{ 945 pad = true; 946 } 947 } 948 rs = (pad) ? this.rowSpacing : '0'; 949 950 td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+ 951 '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+ 952 '</div></td>'); 953 td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>'); 954 if (this.escapeHtml){ 955 td2.text(lt); 956 } 957 else { 958 td2.html(lt); 959 } 960 if (reverse) { 961 td2.prependTo(tr); 962 td1.prependTo(tr); 963 } 964 else { 965 td1.appendTo(tr); 966 td2.appendTo(tr); 967 } 968 pad = true; 969 } 970 idx++; 971 } 972 } 973 } 974 } 975 return this._elem; 976 }; 977 978 979 // setup default renderers for axes and legend so user doesn't have to 980 // called with scope of plot 981 function preInit(target, data, options) { 982 // debugger 983 options = options || {}; 984 options.axesDefaults = options.axesDefaults || {}; 985 options.legend = options.legend || {}; 986 options.seriesDefaults = options.seriesDefaults || {}; 987 options.grid = options.grid || {}; 988 989 // only set these if there is a gauge series 990 var setopts = false; 991 if (options.seriesDefaults.renderer == $.jqplot.MeterGaugeRenderer) { 992 setopts = true; 993 } 994 else if (options.series) { 995 for (var i=0; i < options.series.length; i++) { 996 if (options.series[i].renderer == $.jqplot.MeterGaugeRenderer) { 997 setopts = true; 998 } 999 } 1000 } 1001 1002 if (setopts) { 1003 options.axesDefaults.renderer = $.jqplot.MeterGaugeAxisRenderer; 1004 options.legend.renderer = $.jqplot.MeterGaugeLegendRenderer; 1005 options.legend.preDraw = true; 1006 options.grid.background = options.grid.background || 'white'; 1007 options.grid.drawGridlines = false; 1008 options.grid.borderWidth = (options.grid.borderWidth != null) ? options.grid.borderWidth : 0; 1009 options.grid.shadow = (options.grid.shadow != null) ? options.grid.shadow : false; 1010 } 1011 } 1012 1013 // called with scope of plot 1014 function postParseOptions(options) { 1015 // 1016 } 1017 1018 $.jqplot.preInitHooks.push(preInit); 1019 $.jqplot.postParseOptionsHooks.push(postParseOptions); 1020 1021 $.jqplot.MeterGaugeTickRenderer = function() { 1022 $.jqplot.AxisTickRenderer.call(this); 1023 }; 1024 1025 $.jqplot.MeterGaugeTickRenderer.prototype = new $.jqplot.AxisTickRenderer(); 1026 $.jqplot.MeterGaugeTickRenderer.prototype.constructor = $.jqplot.MeterGaugeTickRenderer; 1027 1028 })(jQuery); 1029 1030
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:08:37 2014 | Cross-referenced by PHPXref 0.7.1 |