Blame | Letzte Änderung | Log anzeigen | RSS feed
/*** jqPlot* Pure JavaScript plotting plugin using jQuery** Version: 1.0.8* Revision: 1250** 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.MekkoRenderer* Draws a Mekko style chart which shows 3 dimensional data on a 2 dimensional graph.* the <$.jqplot.MekkoAxisRenderer> should be used with mekko charts. The mekko renderer* overrides the default legend renderer with its own $.jqplot.MekkoLegendRenderer* which allows more flexibility to specify number of rows and columns in the legend.** Data is specified per bar in the chart. You can specify data as an array of y values, or as* an array of [label, value] pairs. Note that labels are used only on the first series.* Labels on subsequent series are ignored:** > bar1 = [['shirts', 8],['hats', 14],['shoes', 6],['gloves', 16],['dolls', 12]];* > bar2 = [15,6,9,13,6];* > bar3 = [['grumpy',4],['sneezy',2],['happy',7],['sleepy',9],['doc',7]];** If you want to place labels for each bar under the axis, you use the barLabels option on* the axes. The bar labels can be styled with the ".jqplot-mekko-barLabel" css class.** > barLabels = ['Mickey Mouse', 'Donald Duck', 'Goofy'];* > axes:{xaxis:{barLabels:barLabels}}**/$.jqplot.MekkoRenderer = function(){this.shapeRenderer = new $.jqplot.ShapeRenderer();// prop: borderColor// color of the borders between areas on the chartthis.borderColor = null;// prop: showBorders// True to draw borders lines between areas on the chart.// False will draw borders lines with the same color as the area.this.showBorders = true;};// called with scope of series.$.jqplot.MekkoRenderer.prototype.init = function(options, plot) {this.fill = false;this.fillRect = true;this.strokeRect = true;this.shadow = false;// width of bar on x axis.this._xwidth = 0;this._xstart = 0;$.extend(true, this.renderer, options);// set the shape renderer optionsvar opts = {lineJoin:'miter', lineCap:'butt', isarc:false, fillRect:this.fillRect, strokeRect:this.strokeRect};this.renderer.shapeRenderer.init(opts);plot.axes.x2axis._series.push(this);this._type = 'mekko';};// Method: setGridData// converts the user data values to grid coordinates and stores them// in the gridData array. Will convert user data into appropriate// rectangles.// Called with scope of a series.$.jqplot.MekkoRenderer.prototype.setGridData = function(plot) {// recalculate the grid datavar xp = this._xaxis.series_u2p;var yp = this._yaxis.series_u2p;var data = this._plotData;this.gridData = [];// figure out width on x axis.// this._xwidth = this._sumy / plot._sumy * this.canvas.getWidth();this._xwidth = xp(this._sumy) - xp(0);if (this.index>0) {this._xstart = plot.series[this.index-1]._xstart + plot.series[this.index-1]._xwidth;}var totheight = this.canvas.getHeight();var sumy = 0;var cury;var curheight;for (var i=0; i<data.length; i++) {if (data[i] != null) {sumy += data[i][1];cury = totheight - (sumy / this._sumy * totheight);curheight = data[i][1] / this._sumy * totheight;this.gridData.push([this._xstart, cury, this._xwidth, curheight]);}}};// Method: makeGridData// converts any arbitrary data values to grid coordinates and// returns them. This method exists so that plugins can use a series'// linerenderer to generate grid data points without overwriting the// grid data associated with that series.// Called with scope of a series.$.jqplot.MekkoRenderer.prototype.makeGridData = function(data, plot) {// recalculate the grid data// figure out width on x axis.var xp = this._xaxis.series_u2p;var totheight = this.canvas.getHeight();var sumy = 0;var cury;var curheight;var gd = [];for (var i=0; i<data.length; i++) {if (data[i] != null) {sumy += data[i][1];cury = totheight - (sumy / this._sumy * totheight);curheight = data[i][1] / this._sumy * totheight;gd.push([this._xstart, cury, this._xwidth, curheight]);}}return gd;};// called within scope of series.$.jqplot.MekkoRenderer.prototype.draw = function(ctx, gd, options) {var i;var opts = (options != undefined) ? options : {};var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;var colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors);ctx.save();if (gd.length) {if (showLine) {for (i=0; i<gd.length; i++){opts.fillStyle = colorGenerator.next();if (this.renderer.showBorders) {opts.strokeStyle = this.renderer.borderColor;}else {opts.strokeStyle = opts.fillStyle;}this.renderer.shapeRenderer.draw(ctx, gd[i], opts);}}}ctx.restore();};$.jqplot.MekkoRenderer.prototype.drawShadow = function(ctx, gd, options) {// This is a no-op, no shadows on mekko charts.};/*** Class: $.jqplot.MekkoLegendRenderer* Legend renderer used by mekko charts with options for* controlling number or rows and columns as well as placement* outside of plot area.**/$.jqplot.MekkoLegendRenderer = function(){//};$.jqplot.MekkoLegendRenderer.prototype.init = function(options) {// prop: numberRows// Maximum number of rows in the legend. 0 or null for unlimited.this.numberRows = null;// prop: numberColumns// Maximum number of columns in the legend. 0 or null for unlimited.this.numberColumns = null;// this will override the placement option on the Legend objectthis.placement = "outside";$.extend(true, this, options);};// called with scope of legend$.jqplot.MekkoLegendRenderer.prototype.draw = function() {var legend = this;if (this.show) {var series = this._series;var ss = 'position:absolute;';ss += (this.background) ? 'background:'+this.background+';' : '';ss += (this.border) ? 'border:'+this.border+';' : '';ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';ss += (this.textColor) ? 'color:'+this.textColor+';' : '';this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');// Mekko charts legends don't go by number of series, but by number of data points// in the series. Refactor things here for that.var pad = false,reverse = true, // mekko charts are always stacked, so reversenr, nc;var s = series[0];var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors);if (s.show) {var pd = s.data;if (this.numberRows) {nr = this.numberRows;if (!this.numberColumns){nc = Math.ceil(pd.length/nr);}else{nc = this.numberColumns;}}else if (this.numberColumns) {nc = this.numberColumns;nr = Math.ceil(pd.length/this.numberColumns);}else {nr = pd.length;nc = 1;}var i, j, tr, td1, td2, lt, rs, color;var idx = 0;for (i=0; i<nr; i++) {if (reverse){tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem);}else{tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem);}for (j=0; j<nc; j++) {if (idx < pd.length) {lt = this.labels[idx] || pd[idx][0].toString();color = colorGenerator.next();if (!reverse){if (i>0){pad = true;}else{pad = false;}}else{if (i == nr -1){pad = false;}else{pad = true;}}rs = (pad) ? this.rowSpacing : '0';td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+'<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+'</div></td>');td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');if (this.escapeHtml){td2.text(lt);}else {td2.html(lt);}if (reverse) {td2.prependTo(tr);td1.prependTo(tr);}else {td1.appendTo(tr);td2.appendTo(tr);}pad = true;}idx++;}}tr = null;td1 = null;td2 = null;}}return this._elem;};$.jqplot.MekkoLegendRenderer.prototype.pack = function(offsets) {if (this.show) {// fake a grid for positioningvar grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom};if (this.placement == 'insideGrid') {switch (this.location) {case 'nw':var a = grid._left + this.xoffset;var b = grid._top + this.yoffset;this._elem.css('left', a);this._elem.css('top', b);break;case 'n':var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;var b = grid._top + this.yoffset;this._elem.css('left', a);this._elem.css('top', b);break;case 'ne':var a = offsets.right + this.xoffset;var b = grid._top + this.yoffset;this._elem.css({right:a, top:b});break;case 'e':var a = offsets.right + this.xoffset;var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;this._elem.css({right:a, top:b});break;case 'se':var a = offsets.right + this.xoffset;var b = offsets.bottom + this.yoffset;this._elem.css({right:a, bottom:b});break;case 's':var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;var b = offsets.bottom + this.yoffset;this._elem.css({left:a, bottom:b});break;case 'sw':var a = grid._left + this.xoffset;var b = offsets.bottom + this.yoffset;this._elem.css({left:a, bottom:b});break;case 'w':var a = grid._left + this.xoffset;var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;this._elem.css({left:a, top:b});break;default: // same as 'se'var a = grid._right - this.xoffset;var b = grid._bottom + this.yoffset;this._elem.css({right:a, bottom:b});break;}}else {switch (this.location) {case 'nw':var a = this._plotDimensions.width - grid._left + this.xoffset;var b = grid._top + this.yoffset;this._elem.css('right', a);this._elem.css('top', b);break;case 'n':var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;var b = this._plotDimensions.height - grid._top + this.yoffset;this._elem.css('left', a);this._elem.css('bottom', b);break;case 'ne':var a = this._plotDimensions.width - offsets.right + this.xoffset;var b = grid._top + this.yoffset;this._elem.css({left:a, top:b});break;case 'e':var a = this._plotDimensions.width - offsets.right + this.xoffset;var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;this._elem.css({left:a, top:b});break;case 'se':var a = this._plotDimensions.width - offsets.right + this.xoffset;var b = offsets.bottom + this.yoffset;this._elem.css({left:a, bottom:b});break;case 's':var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;var b = this._plotDimensions.height - offsets.bottom + this.yoffset;this._elem.css({left:a, top:b});break;case 'sw':var a = this._plotDimensions.width - grid._left + this.xoffset;var b = offsets.bottom + this.yoffset;this._elem.css({right:a, bottom:b});break;case 'w':var a = this._plotDimensions.width - grid._left + this.xoffset;var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;this._elem.css({right:a, top:b});break;default: // same as 'se'var a = grid._right - this.xoffset;var b = grid._bottom + this.yoffset;this._elem.css({right:a, bottom:b});break;}}}};// setup default renderers for axes and legend so user doesn't have to// called with scope of plotfunction preInit(target, data, options) {options = options || {};options.axesDefaults = options.axesDefaults || {};options.legend = options.legend || {};options.seriesDefaults = options.seriesDefaults || {};var setopts = false;if (options.seriesDefaults.renderer == $.jqplot.MekkoRenderer) {setopts = true;}else if (options.series) {for (var i=0; i < options.series.length; i++) {if (options.series[i].renderer == $.jqplot.MekkoRenderer) {setopts = true;}}}if (setopts) {options.axesDefaults.renderer = $.jqplot.MekkoAxisRenderer;options.legend.renderer = $.jqplot.MekkoLegendRenderer;options.legend.preDraw = true;}}$.jqplot.preInitHooks.push(preInit);})(jQuery);