| /** | 
|  * 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 chart | 
|         this.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 options | 
|         var 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 data | 
|         var 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 object | 
|         this.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 reverse | 
|                 nr, 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 positioning | 
|             var 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 plot | 
|     function 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);     |