/** * jqPlot * Pure JavaScript plotting plugin using jQuery * * Version: @VERSION * Revision: @REVISION * * Copyright (c) 2009-2013 Chris Leonello * jqPlot is currently available for use in all personal or commercial projects * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can * choose the license that best suits your project and use it accordingly. * * Although not required, the author would appreciate an email letting him * know of any substantial use of jqPlot. You can reach the author at: * chris at jqplot dot com or see http://www.jqplot.com/info.php . * * If you are feeling kind and generous, consider supporting the project by * making a donation at: http://www.jqplot.com/donate.php . * * sprintf functions contained in jqplot.sprintf.js by Ash Searle: * * version 2007.04.27 * author Ash Searle * http://hexmen.com/blog/2007/03/printf-sprintf/ * http://hexmen.com/js/sprintf.js * The author (Ash Searle) has placed this code in the public domain: * "This code is unrestricted: you are free to use it however you like." * */ (function($) { /** * class: $.jqplot.CategoryAxisRenderer * A plugin for jqPlot to render a category style axis, with equal pixel spacing between y data values of a series. * * To use this renderer, include the plugin in your source * > * * and supply the appropriate options to your plot * * > {axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer}}} **/ $.jqplot.CategoryAxisRenderer = function(options) { $.jqplot.LinearAxisRenderer.call(this); // prop: sortMergedLabels // True to sort tick labels when labels are created by merging // x axis values from multiple series. That is, say you have // two series like: // > line1 = [[2006, 4], [2008, 9], [2009, 16]]; // > line2 = [[2006, 3], [2007, 7], [2008, 6]]; // If no label array is specified, tick labels will be collected // from the x values of the series. With sortMergedLabels // set to true, tick labels will be: // > [2006, 2007, 2008, 2009] // With sortMergedLabels set to false, tick labels will be: // > [2006, 2008, 2009, 2007] // // Note, this property is specified on the renderOptions for the // axes when creating a plot: // > axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer, rendererOptions:{sortMergedLabels:true}}} this.sortMergedLabels = false; }; $.jqplot.CategoryAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); $.jqplot.CategoryAxisRenderer.prototype.constructor = $.jqplot.CategoryAxisRenderer; $.jqplot.CategoryAxisRenderer.prototype.init = function(options){ this.groups = 1; this.groupLabels = []; this._groupLabels = []; this._grouped = false; this._barsPerGroup = null; this.reverse = false; // prop: tickRenderer // A class of a rendering engine for creating the ticks labels displayed on the plot, // See <$.jqplot.AxisTickRenderer>. // this.tickRenderer = $.jqplot.AxisTickRenderer; // this.labelRenderer = $.jqplot.AxisLabelRenderer; $.extend(true, this, {tickOptions:{formatString:'%d'}}, options); var db = this._dataBounds; // Go through all the series attached to this axis and find // the min/max bounds for this axis. for (var i=0; i db.max || db.max == null) { db.max = d[j][0]; } } else { if (d[j][1] < db.min || db.min == null) { db.min = d[j][1]; } if (d[j][1] > db.max || db.max == null) { db.max = d[j][1]; } } } } if (this.groupLabels.length) { this.groups = this.groupLabels.length; } }; $.jqplot.CategoryAxisRenderer.prototype.createTicks = function() { // we're are operating on an axis here var ticks = this._ticks; var userTicks = this.ticks; var name = this.name; // databounds were set on axis initialization. var db = this._dataBounds; var dim, interval; var min, max; var pos1, pos2; var tt, i; // if we already have ticks, use them. if (userTicks.length) { // adjust with blanks if we have groups if (this.groups > 1 && !this._grouped) { var l = userTicks.length; var skip = parseInt(l/this.groups, 10); var count = 0; for (var i=skip; i 1 && !this._grouped) { var l = labels.length; var skip = parseInt(l/this.groups, 10); var count = 0; for (var i=skip; i0 && track'); if (this.name == 'xaxis' || this.name == 'x2axis') { this._elem.width(this._plotDimensions.width); } else { this._elem.height(this._plotDimensions.height); } // create a _label object. this.labelOptions.axis = this.name; this._label = new this.labelRenderer(this.labelOptions); if (this._label.show) { var elem = this._label.draw(ctx, plot); elem.appendTo(this._elem); } var t = this._ticks; for (var i=0; i'); elem.html(this.groupLabels[i]); this._groupLabels.push(elem); elem.appendTo(this._elem); } } return this._elem; }; // called with scope of axis $.jqplot.CategoryAxisRenderer.prototype.set = function() { var dim = 0; var temp; var w = 0; var h = 0; var lshow = (this._label == null) ? false : this._label.show; if (this.show) { var t = this._ticks; for (var i=0; i dim) { dim = temp; } } } var dim2 = 0; for (var i=0; i dim2) { dim2 = temp; } } if (lshow) { w = this._label._elem.outerWidth(true); h = this._label._elem.outerHeight(true); } if (this.name == 'xaxis') { dim += dim2 + h; this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'}); } else if (this.name == 'x2axis') { dim += dim2 + h; this._elem.css({'height':dim+'px', left:'0px', top:'0px'}); } else if (this.name == 'yaxis') { dim += dim2 + w; this._elem.css({'width':dim+'px', left:'0px', top:'0px'}); if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) { this._label._elem.css('width', w+'px'); } } else { dim += dim2 + w; this._elem.css({'width':dim+'px', right:'0px', top:'0px'}); if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) { this._label._elem.css('width', w+'px'); } } } }; // called with scope of axis $.jqplot.CategoryAxisRenderer.prototype.pack = function(pos, offsets) { var ticks = this._ticks; var max = this.max; var min = this.min; var offmax = offsets.max; var offmin = offsets.min; var lshow = (this._label == null) ? false : this._label.show; var i; for (var p in pos) { this._elem.css(p, pos[p]); } this._offsets = offsets; // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left. var pixellength = offmax - offmin; var unitlength = max - min; if (!this.reverse) { // point to unit and unit to point conversions references to Plot DOM element top left corner. this.u2p = function(u){ return (u - min) * pixellength / unitlength + offmin; }; this.p2u = function(p){ return (p - offmin) * unitlength / pixellength + min; }; if (this.name == 'xaxis' || this.name == 'x2axis'){ this.series_u2p = function(u){ return (u - min) * pixellength / unitlength; }; this.series_p2u = function(p){ return p * unitlength / pixellength + min; }; } else { this.series_u2p = function(u){ return (u - max) * pixellength / unitlength; }; this.series_p2u = function(p){ return p * unitlength / pixellength + max; }; } } else { // point to unit and unit to point conversions references to Plot DOM element top left corner. this.u2p = function(u){ return offmin + (max - u) * pixellength / unitlength; }; this.p2u = function(p){ return min + (p - offmin) * unitlength / pixellength; }; if (this.name == 'xaxis' || this.name == 'x2axis'){ this.series_u2p = function(u){ return (max - u) * pixellength / unitlength; }; this.series_p2u = function(p){ return p * unitlength / pixellength + max; }; } else { this.series_u2p = function(u){ return (min - u) * pixellength / unitlength; }; this.series_p2u = function(p){ return p * unitlength / pixellength + min; }; } } if (this.show) { if (this.name == 'xaxis' || this.name == 'x2axis') { for (i=0; i= this._ticks.length-1) continue; // the last tick does not exist as there is no other group in order to have an empty one. if (this._ticks[j]._elem && this._ticks[j].label != " ") { var t = this._ticks[j]._elem; var p = t.position(); mid += p.left + t.outerWidth(true)/2; count++; } } mid = mid/count; this._groupLabels[i].css({'left':(mid - this._groupLabels[i].outerWidth(true)/2)}); this._groupLabels[i].css(labeledge[0], labeledge[1]); } } else { for (i=0; i 0) { shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2; } else { shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2; } break; case 'middle': // if (t.angle > 0) { // shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; // } // else { // shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; // } shim = -t.getHeight()/2; break; default: shim = -t.getHeight()/2; break; } } else { shim = -t.getHeight()/2; } var val = this.u2p(t.value) + shim + 'px'; t._elem.css('top', val); t.pack(); } } var labeledge=['left', 0]; if (lshow) { var h = this._label._elem.outerHeight(true); this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px'); if (this.name == 'yaxis') { this._label._elem.css('left', '0px'); labeledge = ['left', this._label._elem.outerWidth(true)]; } else { this._label._elem.css('right', '0px'); labeledge = ['right', this._label._elem.outerWidth(true)]; } this._label.pack(); } // draw the group labels, position top here, do left after label position. var step = parseInt(this._ticks.length/this.groups, 10) + 1; // step is one more than before as we don't want to have overlaps in loops for (i=0; i= this._ticks.length-1) continue; // the last tick does not exist as there is no other group in order to have an empty one. if (this._ticks[j]._elem && this._ticks[j].label != " ") { var t = this._ticks[j]._elem; var p = t.position(); mid += p.top + t.outerHeight()/2; count++; } } mid = mid/count; this._groupLabels[i].css({'top':mid - this._groupLabels[i].outerHeight()/2}); this._groupLabels[i].css(labeledge[0], labeledge[1]); } } } }; })(jQuery);