| [ 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.CategoryAxisRenderer 34 * A plugin for jqPlot to render a category style axis, with equal pixel spacing between y data values of a series. 35 * 36 * To use this renderer, include the plugin in your source 37 * > <script type="text/javascript" language="javascript" src="plugins/jqplot.categoryAxisRenderer.js"></script> 38 * 39 * and supply the appropriate options to your plot 40 * 41 * > {axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer}}} 42 **/ 43 $.jqplot.CategoryAxisRenderer = function(options) { 44 $.jqplot.LinearAxisRenderer.call(this); 45 // prop: sortMergedLabels 46 // True to sort tick labels when labels are created by merging 47 // x axis values from multiple series. That is, say you have 48 // two series like: 49 // > line1 = [[2006, 4], [2008, 9], [2009, 16]]; 50 // > line2 = [[2006, 3], [2007, 7], [2008, 6]]; 51 // If no label array is specified, tick labels will be collected 52 // from the x values of the series. With sortMergedLabels 53 // set to true, tick labels will be: 54 // > [2006, 2007, 2008, 2009] 55 // With sortMergedLabels set to false, tick labels will be: 56 // > [2006, 2008, 2009, 2007] 57 // 58 // Note, this property is specified on the renderOptions for the 59 // axes when creating a plot: 60 // > axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer, rendererOptions:{sortMergedLabels:true}}} 61 this.sortMergedLabels = false; 62 }; 63 64 $.jqplot.CategoryAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); 65 $.jqplot.CategoryAxisRenderer.prototype.constructor = $.jqplot.CategoryAxisRenderer; 66 67 $.jqplot.CategoryAxisRenderer.prototype.init = function(options){ 68 this.groups = 1; 69 this.groupLabels = []; 70 this._groupLabels = []; 71 this._grouped = false; 72 this._barsPerGroup = null; 73 // prop: tickRenderer 74 // A class of a rendering engine for creating the ticks labels displayed on the plot, 75 // See <$.jqplot.AxisTickRenderer>. 76 // this.tickRenderer = $.jqplot.AxisTickRenderer; 77 // this.labelRenderer = $.jqplot.AxisLabelRenderer; 78 $.extend(true, this, {tickOptions:{formatString:'%d'}}, options); 79 var db = this._dataBounds; 80 // Go through all the series attached to this axis and find 81 // the min/max bounds for this axis. 82 for (var i=0; i<this._series.length; i++) { 83 var s = this._series[i]; 84 if (s.groups) { 85 this.groups = s.groups; 86 } 87 var d = s.data; 88 89 for (var j=0; j<d.length; j++) { 90 if (this.name == 'xaxis' || this.name == 'x2axis') { 91 if (d[j][0] < db.min || db.min == null) { 92 db.min = d[j][0]; 93 } 94 if (d[j][0] > db.max || db.max == null) { 95 db.max = d[j][0]; 96 } 97 } 98 else { 99 if (d[j][1] < db.min || db.min == null) { 100 db.min = d[j][1]; 101 } 102 if (d[j][1] > db.max || db.max == null) { 103 db.max = d[j][1]; 104 } 105 } 106 } 107 } 108 109 if (this.groupLabels.length) { 110 this.groups = this.groupLabels.length; 111 } 112 }; 113 114 115 $.jqplot.CategoryAxisRenderer.prototype.createTicks = function() { 116 // we're are operating on an axis here 117 var ticks = this._ticks; 118 var userTicks = this.ticks; 119 var name = this.name; 120 // databounds were set on axis initialization. 121 var db = this._dataBounds; 122 var dim, interval; 123 var min, max; 124 var pos1, pos2; 125 var tt, i; 126 127 // if we already have ticks, use them. 128 if (userTicks.length) { 129 // adjust with blanks if we have groups 130 if (this.groups > 1 && !this._grouped) { 131 var l = userTicks.length; 132 var skip = parseInt(l/this.groups, 10); 133 var count = 0; 134 for (var i=skip; i<l; i+=skip) { 135 userTicks.splice(i+count, 0, ' '); 136 count++; 137 } 138 this._grouped = true; 139 } 140 this.min = 0.5; 141 this.max = userTicks.length + 0.5; 142 var range = this.max - this.min; 143 this.numberTicks = 2*userTicks.length + 1; 144 for (i=0; i<userTicks.length; i++){ 145 tt = this.min + 2 * i * range / (this.numberTicks-1); 146 // need a marker before and after the tick 147 var t = new this.tickRenderer(this.tickOptions); 148 t.showLabel = false; 149 // t.showMark = true; 150 t.setTick(tt, this.name); 151 this._ticks.push(t); 152 var t = new this.tickRenderer(this.tickOptions); 153 t.label = userTicks[i]; 154 // t.showLabel = true; 155 t.showMark = false; 156 t.showGridline = false; 157 t.setTick(tt+0.5, this.name); 158 this._ticks.push(t); 159 } 160 // now add the last tick at the end 161 var t = new this.tickRenderer(this.tickOptions); 162 t.showLabel = false; 163 // t.showMark = true; 164 t.setTick(tt+1, this.name); 165 this._ticks.push(t); 166 } 167 168 // we don't have any ticks yet, let's make some! 169 else { 170 if (name == 'xaxis' || name == 'x2axis') { 171 dim = this._plotDimensions.width; 172 } 173 else { 174 dim = this._plotDimensions.height; 175 } 176 177 // if min, max and number of ticks specified, user can't specify interval. 178 if (this.min != null && this.max != null && this.numberTicks != null) { 179 this.tickInterval = null; 180 } 181 182 // if max, min, and interval specified and interval won't fit, ignore interval. 183 if (this.min != null && this.max != null && this.tickInterval != null) { 184 if (parseInt((this.max-this.min)/this.tickInterval, 10) != (this.max-this.min)/this.tickInterval) { 185 this.tickInterval = null; 186 } 187 } 188 189 // find out how many categories are in the lines and collect labels 190 var labels = []; 191 var numcats = 0; 192 var min = 0.5; 193 var max, val; 194 var isMerged = false; 195 for (var i=0; i<this._series.length; i++) { 196 var s = this._series[i]; 197 for (var j=0; j<s.data.length; j++) { 198 if (this.name == 'xaxis' || this.name == 'x2axis') { 199 val = s.data[j][0]; 200 } 201 else { 202 val = s.data[j][1]; 203 } 204 if ($.inArray(val, labels) == -1) { 205 isMerged = true; 206 numcats += 1; 207 labels.push(val); 208 } 209 } 210 } 211 212 if (isMerged && this.sortMergedLabels) { 213 labels.sort(function(a,b) { return a - b; }); 214 } 215 216 // keep a reference to these tick labels to use for redrawing plot (see bug #57) 217 this.ticks = labels; 218 219 // now bin the data values to the right lables. 220 for (var i=0; i<this._series.length; i++) { 221 var s = this._series[i]; 222 for (var j=0; j<s.data.length; j++) { 223 if (this.name == 'xaxis' || this.name == 'x2axis') { 224 val = s.data[j][0]; 225 } 226 else { 227 val = s.data[j][1]; 228 } 229 // for category axis, force the values into category bins. 230 // we should have the value in the label array now. 231 var idx = $.inArray(val, labels)+1; 232 if (this.name == 'xaxis' || this.name == 'x2axis') { 233 s.data[j][0] = idx; 234 } 235 else { 236 s.data[j][1] = idx; 237 } 238 } 239 } 240 241 // adjust with blanks if we have groups 242 if (this.groups > 1 && !this._grouped) { 243 var l = labels.length; 244 var skip = parseInt(l/this.groups, 10); 245 var count = 0; 246 for (var i=skip; i<l; i+=skip+1) { 247 labels[i] = ' '; 248 } 249 this._grouped = true; 250 } 251 252 max = numcats + 0.5; 253 if (this.numberTicks == null) { 254 this.numberTicks = 2*numcats + 1; 255 } 256 257 var range = max - min; 258 this.min = min; 259 this.max = max; 260 var track = 0; 261 262 // todo: adjust this so more ticks displayed. 263 var maxVisibleTicks = parseInt(3+dim/10, 10); 264 var skip = parseInt(numcats/maxVisibleTicks, 10); 265 266 if (this.tickInterval == null) { 267 268 this.tickInterval = range / (this.numberTicks-1); 269 270 } 271 // if tickInterval is specified, we will ignore any computed maximum. 272 for (var i=0; i<this.numberTicks; i++){ 273 tt = this.min + i * this.tickInterval; 274 var t = new this.tickRenderer(this.tickOptions); 275 // if even tick, it isn't a category, it's a divider 276 if (i/2 == parseInt(i/2, 10)) { 277 t.showLabel = false; 278 t.showMark = true; 279 } 280 else { 281 if (skip>0 && track<skip) { 282 t.showLabel = false; 283 track += 1; 284 } 285 else { 286 t.showLabel = true; 287 track = 0; 288 } 289 t.label = t.formatter(t.formatString, labels[(i-1)/2]); 290 t.showMark = false; 291 t.showGridline = false; 292 } 293 t.setTick(tt, this.name); 294 this._ticks.push(t); 295 } 296 } 297 298 }; 299 300 // called with scope of axis 301 $.jqplot.CategoryAxisRenderer.prototype.draw = function(ctx, plot) { 302 if (this.show) { 303 // populate the axis label and value properties. 304 // createTicks is a method on the renderer, but 305 // call it within the scope of the axis. 306 this.renderer.createTicks.call(this); 307 // fill a div with axes labels in the right direction. 308 // Need to pregenerate each axis to get it's bounds and 309 // position it and the labels correctly on the plot. 310 var dim=0; 311 var temp; 312 // Added for theming. 313 if (this._elem) { 314 // this._elem.empty(); 315 // Memory Leaks patch 316 this._elem.emptyForce(); 317 } 318 319 this._elem = this._elem || $('<div class="jqplot-axis jqplot-'+this.name+'" style="position:absolute;"></div>'); 320 321 if (this.name == 'xaxis' || this.name == 'x2axis') { 322 this._elem.width(this._plotDimensions.width); 323 } 324 else { 325 this._elem.height(this._plotDimensions.height); 326 } 327 328 // create a _label object. 329 this.labelOptions.axis = this.name; 330 this._label = new this.labelRenderer(this.labelOptions); 331 if (this._label.show) { 332 var elem = this._label.draw(ctx, plot); 333 elem.appendTo(this._elem); 334 } 335 336 var t = this._ticks; 337 for (var i=0; i<t.length; i++) { 338 var tick = t[i]; 339 if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) { 340 var elem = tick.draw(ctx, plot); 341 elem.appendTo(this._elem); 342 } 343 } 344 345 this._groupLabels = []; 346 // now make group labels 347 for (var i=0; i<this.groupLabels.length; i++) 348 { 349 var elem = $('<div style="position:absolute;" class="jqplot-'+this.name+'-groupLabel"></div>'); 350 elem.html(this.groupLabels[i]); 351 this._groupLabels.push(elem); 352 elem.appendTo(this._elem); 353 } 354 } 355 return this._elem; 356 }; 357 358 // called with scope of axis 359 $.jqplot.CategoryAxisRenderer.prototype.set = function() { 360 var dim = 0; 361 var temp; 362 var w = 0; 363 var h = 0; 364 var lshow = (this._label == null) ? false : this._label.show; 365 if (this.show) { 366 var t = this._ticks; 367 for (var i=0; i<t.length; i++) { 368 var tick = t[i]; 369 if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) { 370 if (this.name == 'xaxis' || this.name == 'x2axis') { 371 temp = tick._elem.outerHeight(true); 372 } 373 else { 374 temp = tick._elem.outerWidth(true); 375 } 376 if (temp > dim) { 377 dim = temp; 378 } 379 } 380 } 381 382 var dim2 = 0; 383 for (var i=0; i<this._groupLabels.length; i++) { 384 var l = this._groupLabels[i]; 385 if (this.name == 'xaxis' || this.name == 'x2axis') { 386 temp = l.outerHeight(true); 387 } 388 else { 389 temp = l.outerWidth(true); 390 } 391 if (temp > dim2) { 392 dim2 = temp; 393 } 394 } 395 396 if (lshow) { 397 w = this._label._elem.outerWidth(true); 398 h = this._label._elem.outerHeight(true); 399 } 400 if (this.name == 'xaxis') { 401 dim += dim2 + h; 402 this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'}); 403 } 404 else if (this.name == 'x2axis') { 405 dim += dim2 + h; 406 this._elem.css({'height':dim+'px', left:'0px', top:'0px'}); 407 } 408 else if (this.name == 'yaxis') { 409 dim += dim2 + w; 410 this._elem.css({'width':dim+'px', left:'0px', top:'0px'}); 411 if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) { 412 this._label._elem.css('width', w+'px'); 413 } 414 } 415 else { 416 dim += dim2 + w; 417 this._elem.css({'width':dim+'px', right:'0px', top:'0px'}); 418 if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) { 419 this._label._elem.css('width', w+'px'); 420 } 421 } 422 } 423 }; 424 425 // called with scope of axis 426 $.jqplot.CategoryAxisRenderer.prototype.pack = function(pos, offsets) { 427 var ticks = this._ticks; 428 var max = this.max; 429 var min = this.min; 430 var offmax = offsets.max; 431 var offmin = offsets.min; 432 var lshow = (this._label == null) ? false : this._label.show; 433 var i; 434 435 for (var p in pos) { 436 this._elem.css(p, pos[p]); 437 } 438 439 this._offsets = offsets; 440 // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left. 441 var pixellength = offmax - offmin; 442 var unitlength = max - min; 443 444 // point to unit and unit to point conversions references to Plot DOM element top left corner. 445 this.p2u = function(p){ 446 return (p - offmin) * unitlength / pixellength + min; 447 }; 448 449 this.u2p = function(u){ 450 return (u - min) * pixellength / unitlength + offmin; 451 }; 452 453 if (this.name == 'xaxis' || this.name == 'x2axis'){ 454 this.series_u2p = function(u){ 455 return (u - min) * pixellength / unitlength; 456 }; 457 this.series_p2u = function(p){ 458 return p * unitlength / pixellength + min; 459 }; 460 } 461 462 else { 463 this.series_u2p = function(u){ 464 return (u - max) * pixellength / unitlength; 465 }; 466 this.series_p2u = function(p){ 467 return p * unitlength / pixellength + max; 468 }; 469 } 470 471 if (this.show) { 472 if (this.name == 'xaxis' || this.name == 'x2axis') { 473 for (i=0; i<ticks.length; i++) { 474 var t = ticks[i]; 475 if (t.show && t.showLabel) { 476 var shim; 477 478 if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) { 479 // will need to adjust auto positioning based on which axis this is. 480 var temp = (this.name == 'xaxis') ? 1 : -1; 481 switch (t.labelPosition) { 482 case 'auto': 483 // position at end 484 if (temp * t.angle < 0) { 485 shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; 486 } 487 // position at start 488 else { 489 shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; 490 } 491 break; 492 case 'end': 493 shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; 494 break; 495 case 'start': 496 shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; 497 break; 498 case 'middle': 499 shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; 500 break; 501 default: 502 shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; 503 break; 504 } 505 } 506 else { 507 shim = -t.getWidth()/2; 508 } 509 var val = this.u2p(t.value) + shim + 'px'; 510 t._elem.css('left', val); 511 t.pack(); 512 } 513 } 514 515 var labeledge=['bottom', 0]; 516 if (lshow) { 517 var w = this._label._elem.outerWidth(true); 518 this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px'); 519 if (this.name == 'xaxis') { 520 this._label._elem.css('bottom', '0px'); 521 labeledge = ['bottom', this._label._elem.outerHeight(true)]; 522 } 523 else { 524 this._label._elem.css('top', '0px'); 525 labeledge = ['top', this._label._elem.outerHeight(true)]; 526 } 527 this._label.pack(); 528 } 529 530 // draw the group labels 531 var step = parseInt(this._ticks.length/this.groups, 10); 532 for (i=0; i<this._groupLabels.length; i++) { 533 var mid = 0; 534 var count = 0; 535 for (var j=i*step; j<=(i+1)*step; j++) { 536 if (this._ticks[j]._elem && this._ticks[j].label != " ") { 537 var t = this._ticks[j]._elem; 538 var p = t.position(); 539 mid += p.left + t.outerWidth(true)/2; 540 count++; 541 } 542 } 543 mid = mid/count; 544 this._groupLabels[i].css({'left':(mid - this._groupLabels[i].outerWidth(true)/2)}); 545 this._groupLabels[i].css(labeledge[0], labeledge[1]); 546 } 547 } 548 else { 549 for (i=0; i<ticks.length; i++) { 550 var t = ticks[i]; 551 if (t.show && t.showLabel) { 552 var shim; 553 if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) { 554 // will need to adjust auto positioning based on which axis this is. 555 var temp = (this.name == 'yaxis') ? 1 : -1; 556 switch (t.labelPosition) { 557 case 'auto': 558 // position at end 559 case 'end': 560 if (temp * t.angle < 0) { 561 shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2; 562 } 563 else { 564 shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2; 565 } 566 break; 567 case 'start': 568 if (t.angle > 0) { 569 shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2; 570 } 571 else { 572 shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2; 573 } 574 break; 575 case 'middle': 576 // if (t.angle > 0) { 577 // shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; 578 // } 579 // else { 580 // shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; 581 // } 582 shim = -t.getHeight()/2; 583 break; 584 default: 585 shim = -t.getHeight()/2; 586 break; 587 } 588 } 589 else { 590 shim = -t.getHeight()/2; 591 } 592 593 var val = this.u2p(t.value) + shim + 'px'; 594 t._elem.css('top', val); 595 t.pack(); 596 } 597 } 598 599 var labeledge=['left', 0]; 600 if (lshow) { 601 var h = this._label._elem.outerHeight(true); 602 this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px'); 603 if (this.name == 'yaxis') { 604 this._label._elem.css('left', '0px'); 605 labeledge = ['left', this._label._elem.outerWidth(true)]; 606 } 607 else { 608 this._label._elem.css('right', '0px'); 609 labeledge = ['right', this._label._elem.outerWidth(true)]; 610 } 611 this._label.pack(); 612 } 613 614 // draw the group labels, position top here, do left after label position. 615 var step = parseInt(this._ticks.length/this.groups, 10); 616 for (i=0; i<this._groupLabels.length; i++) { 617 var mid = 0; 618 var count = 0; 619 for (var j=i*step; j<=(i+1)*step; j++) { 620 if (this._ticks[j]._elem && this._ticks[j].label != " ") { 621 var t = this._ticks[j]._elem; 622 var p = t.position(); 623 mid += p.top + t.outerHeight()/2; 624 count++; 625 } 626 } 627 mid = mid/count; 628 this._groupLabels[i].css({'top':mid - this._groupLabels[i].outerHeight()/2}); 629 this._groupLabels[i].css(labeledge[0], labeledge[1]); 630 631 } 632 } 633 } 634 }; 635 636 637 })(jQuery);
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 |