Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Scripts/jqPlot/plugins/jqplot.mekkoRenderer.js @ 9646

Last change on this file since 9646 was 9617, checked in by pfleck, 12 years ago

#2063:
Started integrating Hive statistics into statistics web project.
Added jqPlot library for charting.

File size: 18.5 KB
Line 
1/**
2 * jqPlot
3 * Pure JavaScript plotting plugin using jQuery
4 *
5 * Version: 1.0.0b2_r1012
6 *
7 * Copyright (c) 2009-2011 Chris Leonello
8 * jqPlot is currently available for use in all personal or commercial projects
9 * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
10 * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
11 * choose the license that best suits your project and use it accordingly.
12 *
13 * Although not required, the author would appreciate an email letting him
14 * know of any substantial use of jqPlot.  You can reach the author at:
15 * chris at jqplot dot com or see http://www.jqplot.com/info.php .
16 *
17 * If you are feeling kind and generous, consider supporting the project by
18 * making a donation at: http://www.jqplot.com/donate.php .
19 *
20 * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
21 *
22 *     version 2007.04.27
23 *     author Ash Searle
24 *     http://hexmen.com/blog/2007/03/printf-sprintf/
25 *     http://hexmen.com/js/sprintf.js
26 *     The author (Ash Searle) has placed this code in the public domain:
27 *     "This code is unrestricted: you are free to use it however you like."
28 *
29 */
30(function($) {
31    /**
32     * Class: $.jqplot.MekkoRenderer
33     * Draws a Mekko style chart which shows 3 dimensional data on a 2 dimensional graph.
34     * the <$.jqplot.MekkoAxisRenderer> should be used with mekko charts.  The mekko renderer
35     * overrides the default legend renderer with it's own $.jqplot.MekkoLegendRenderer
36     * which allows more flexibility to specify number of rows and columns in the legend.
37     *
38     * Data is specified per bar in the chart.  You can specify data as an array of y values, or as
39     * an array of [label, value] pairs.  Note that labels are used only on the first series. 
40     * Labels on subsequent series are ignored:
41     *
42     * > bar1 = [['shirts', 8],['hats', 14],['shoes', 6],['gloves', 16],['dolls', 12]];
43     * > bar2 = [15,6,9,13,6];
44     * > bar3 = [['grumpy',4],['sneezy',2],['happy',7],['sleepy',9],['doc',7]];
45     *
46     * If you want to place labels for each bar under the axis, you use the barLabels option on
47     * the axes.  The bar labels can be styled with the ".jqplot-mekko-barLabel" css class.
48     *
49     * > barLabels = ['Mickey Mouse', 'Donald Duck', 'Goofy'];
50     * > axes:{xaxis:{barLabels:barLabels}}
51     *
52     */
53   
54   
55    $.jqplot.MekkoRenderer = function(){
56        this.shapeRenderer = new $.jqplot.ShapeRenderer();
57        // prop: borderColor
58        // color of the borders between areas on the chart
59        this.borderColor = null;
60        // prop: showBorders
61        // True to draw borders lines between areas on the chart.
62        // False will draw borders lines with the same color as the area.
63        this.showBorders = true;
64    };
65   
66    // called with scope of series.
67    $.jqplot.MekkoRenderer.prototype.init = function(options, plot) {
68        this.fill = false;
69        this.fillRect = true;
70        this.strokeRect = true;
71        this.shadow = false;
72        // width of bar on x axis.
73        this._xwidth = 0;
74        this._xstart = 0;
75        $.extend(true, this.renderer, options);
76        // set the shape renderer options
77        var opts = {lineJoin:'miter', lineCap:'butt', isarc:false, fillRect:this.fillRect, strokeRect:this.strokeRect};
78        this.renderer.shapeRenderer.init(opts);
79        plot.axes.x2axis._series.push(this);
80        this._type = 'mekko';
81    };
82   
83    // Method: setGridData
84    // converts the user data values to grid coordinates and stores them
85    // in the gridData array.  Will convert user data into appropriate
86    // rectangles.
87    // Called with scope of a series.
88    $.jqplot.MekkoRenderer.prototype.setGridData = function(plot) {
89        // recalculate the grid data
90        var xp = this._xaxis.series_u2p;
91        var yp = this._yaxis.series_u2p;
92        var data = this._plotData;
93        this.gridData = [];
94        // figure out width on x axis.
95        // this._xwidth = this._sumy / plot._sumy * this.canvas.getWidth();
96        this._xwidth = xp(this._sumy) - xp(0);
97        if (this.index>0) {
98            this._xstart = plot.series[this.index-1]._xstart + plot.series[this.index-1]._xwidth;
99        }
100        var totheight = this.canvas.getHeight();
101        var sumy = 0;
102        var cury;
103        var curheight;
104        for (var i=0; i<data.length; i++) {
105            if (data[i] != null) {
106                sumy += data[i][1];
107                cury = totheight - (sumy / this._sumy * totheight);
108                curheight = data[i][1] / this._sumy * totheight;
109                this.gridData.push([this._xstart, cury, this._xwidth, curheight]);
110            }
111        }
112    };
113   
114    // Method: makeGridData
115    // converts any arbitrary data values to grid coordinates and
116    // returns them.  This method exists so that plugins can use a series'
117    // linerenderer to generate grid data points without overwriting the
118    // grid data associated with that series.
119    // Called with scope of a series.
120    $.jqplot.MekkoRenderer.prototype.makeGridData = function(data, plot) {
121        // recalculate the grid data
122        // figure out width on x axis.
123        var xp = this._xaxis.series_u2p;
124        var totheight = this.canvas.getHeight();
125        var sumy = 0;
126        var cury;
127        var curheight;
128        var gd = [];
129        for (var i=0; i<data.length; i++) {
130            if (data[i] != null) {
131                sumy += data[i][1];
132                cury = totheight - (sumy / this._sumy * totheight);
133                curheight = data[i][1] / this._sumy * totheight;
134                gd.push([this._xstart, cury, this._xwidth, curheight]);
135            }
136        }
137        return gd;
138    };
139   
140
141    // called within scope of series.
142    $.jqplot.MekkoRenderer.prototype.draw = function(ctx, gd, options) {
143        var i;
144        var opts = (options != undefined) ? options : {};
145        var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
146        var colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors);
147        ctx.save();
148        if (gd.length) {
149            if (showLine) {
150                for (i=0; i<gd.length; i++){
151                    opts.fillStyle = colorGenerator.next();
152                    if (this.renderer.showBorders) {
153                        opts.strokeStyle = this.renderer.borderColor;
154                    }
155                    else {
156                        opts.strokeStyle = opts.fillStyle;
157                    }
158                    this.renderer.shapeRenderer.draw(ctx, gd[i], opts);
159                }
160            }
161        }
162       
163        ctx.restore();
164    }; 
165   
166    $.jqplot.MekkoRenderer.prototype.drawShadow = function(ctx, gd, options) {
167        // This is a no-op, no shadows on mekko charts.
168    };
169   
170    /**
171     * Class: $.jqplot.MekkoLegendRenderer
172     * Legend renderer used by mekko charts with options for
173     * controlling number or rows and columns as well as placement
174     * outside of plot area.
175     *
176     */
177    $.jqplot.MekkoLegendRenderer = function(){
178        //
179    };
180   
181    $.jqplot.MekkoLegendRenderer.prototype.init = function(options) {
182        // prop: numberRows
183        // Maximum number of rows in the legend.  0 or null for unlimited.
184        this.numberRows = null;
185        // prop: numberColumns
186        // Maximum number of columns in the legend.  0 or null for unlimited.
187        this.numberColumns = null;
188        // this will override the placement option on the Legend object
189        this.placement = "outside";
190        $.extend(true, this, options);
191    };
192   
193    // called with scope of legend
194    $.jqplot.MekkoLegendRenderer.prototype.draw = function() {
195        var legend = this;
196        if (this.show) {
197            var series = this._series;
198            var ss = 'position:absolute;';
199            ss += (this.background) ? 'background:'+this.background+';' : '';
200            ss += (this.border) ? 'border:'+this.border+';' : '';
201            ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
202            ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
203            ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
204            this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
205            // Mekko charts  legends don't go by number of series, but by number of data points
206            // in the series.  Refactor things here for that.
207           
208            var pad = false,
209                reverse = true,    // mekko charts are always stacked, so reverse
210                nr, nc;
211            var s = series[0];
212            var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors);
213           
214            if (s.show) {
215                var pd = s.data;
216                if (this.numberRows) {
217                    nr = this.numberRows;
218                    if (!this.numberColumns){
219                        nc = Math.ceil(pd.length/nr);
220                    }
221                    else{
222                        nc = this.numberColumns;
223                    }
224                }
225                else if (this.numberColumns) {
226                    nc = this.numberColumns;
227                    nr = Math.ceil(pd.length/this.numberColumns);
228                }
229                else {
230                    nr = pd.length;
231                    nc = 1;
232                }
233               
234                var i, j, tr, td1, td2, lt, rs, color;
235                var idx = 0;   
236               
237                for (i=0; i<nr; i++) {
238                    if (reverse){
239                        tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem);
240                    }
241                    else{
242                        tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem);
243                    }
244                    for (j=0; j<nc; j++) {
245                        if (idx < pd.length) {
246                            lt = this.labels[idx] || pd[idx][0].toString();
247                            color = colorGenerator.next();
248                            if (!reverse){
249                                if (i>0){
250                                    pad = true;
251                                }
252                                else{
253                                    pad = false;
254                                }
255                            }
256                            else{
257                                if (i == nr -1){
258                                    pad = false;
259                                }
260                                else{
261                                    pad = true;
262                                }
263                            }
264                            rs = (pad) ? this.rowSpacing : '0';
265               
266                            td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
267                                '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+
268                                '</div></td>');
269                            td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
270                            if (this.escapeHtml){
271                                td2.text(lt);
272                            }
273                            else {
274                                td2.html(lt);
275                            }
276                            if (reverse) {
277                                td2.prependTo(tr);
278                                td1.prependTo(tr);
279                            }
280                            else {
281                                td1.appendTo(tr);
282                                td2.appendTo(tr);
283                            }
284                            pad = true;
285                        }
286                        idx++;
287                    }   
288                }
289
290                tr = null;
291                td1 = null;
292                td2 = null;
293            }
294        }
295        return this._elem;
296    };
297   
298    $.jqplot.MekkoLegendRenderer.prototype.pack = function(offsets) {
299        if (this.show) {
300            // fake a grid for positioning
301            var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom};       
302            if (this.placement == 'insideGrid') {
303                switch (this.location) {
304                    case 'nw':
305                        var a = grid._left + this.xoffset;
306                        var b = grid._top + this.yoffset;
307                        this._elem.css('left', a);
308                        this._elem.css('top', b);
309                        break;
310                    case 'n':
311                        var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
312                        var b = grid._top + this.yoffset;
313                        this._elem.css('left', a);
314                        this._elem.css('top', b);
315                        break;
316                    case 'ne':
317                        var a = offsets.right + this.xoffset;
318                        var b = grid._top + this.yoffset;
319                        this._elem.css({right:a, top:b});
320                        break;
321                    case 'e':
322                        var a = offsets.right + this.xoffset;
323                        var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
324                        this._elem.css({right:a, top:b});
325                        break;
326                    case 'se':
327                        var a = offsets.right + this.xoffset;
328                        var b = offsets.bottom + this.yoffset;
329                        this._elem.css({right:a, bottom:b});
330                        break;
331                    case 's':
332                        var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
333                        var b = offsets.bottom + this.yoffset;
334                        this._elem.css({left:a, bottom:b});
335                        break;
336                    case 'sw':
337                        var a = grid._left + this.xoffset;
338                        var b = offsets.bottom + this.yoffset;
339                        this._elem.css({left:a, bottom:b});
340                        break;
341                    case 'w':
342                        var a = grid._left + this.xoffset;
343                        var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
344                        this._elem.css({left:a, top:b});
345                        break;
346                    default:  // same as 'se'
347                        var a = grid._right - this.xoffset;
348                        var b = grid._bottom + this.yoffset;
349                        this._elem.css({right:a, bottom:b});
350                        break;
351                }
352               
353            }
354            else {
355                switch (this.location) {
356                    case 'nw':
357                        var a = this._plotDimensions.width - grid._left + this.xoffset;
358                        var b = grid._top + this.yoffset;
359                        this._elem.css('right', a);
360                        this._elem.css('top', b);
361                        break;
362                    case 'n':
363                        var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
364                        var b = this._plotDimensions.height - grid._top + this.yoffset;
365                        this._elem.css('left', a);
366                        this._elem.css('bottom', b);
367                        break;
368                    case 'ne':
369                        var a = this._plotDimensions.width - offsets.right + this.xoffset;
370                        var b = grid._top + this.yoffset;
371                        this._elem.css({left:a, top:b});
372                        break;
373                    case 'e':
374                        var a = this._plotDimensions.width - offsets.right + this.xoffset;
375                        var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
376                        this._elem.css({left:a, top:b});
377                        break;
378                    case 'se':
379                        var a = this._plotDimensions.width - offsets.right + this.xoffset;
380                        var b = offsets.bottom + this.yoffset;
381                        this._elem.css({left:a, bottom:b});
382                        break;
383                    case 's':
384                        var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
385                        var b = this._plotDimensions.height - offsets.bottom + this.yoffset;
386                        this._elem.css({left:a, top:b});
387                        break;
388                    case 'sw':
389                        var a = this._plotDimensions.width - grid._left + this.xoffset;
390                        var b = offsets.bottom + this.yoffset;
391                        this._elem.css({right:a, bottom:b});
392                        break;
393                    case 'w':
394                        var a = this._plotDimensions.width - grid._left + this.xoffset;
395                        var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
396                        this._elem.css({right:a, top:b});
397                        break;
398                    default:  // same as 'se'
399                        var a = grid._right - this.xoffset;
400                        var b = grid._bottom + this.yoffset;
401                        this._elem.css({right:a, bottom:b});
402                        break;
403                }
404            }
405        }
406    };
407   
408    // setup default renderers for axes and legend so user doesn't have to
409    // called with scope of plot
410    function preInit(target, data, options) {
411        options = options || {};
412        options.axesDefaults = options.axesDefaults || {};
413        options.legend = options.legend || {};
414        options.seriesDefaults = options.seriesDefaults || {};
415        var setopts = false;
416        if (options.seriesDefaults.renderer == $.jqplot.MekkoRenderer) {
417            setopts = true;
418        }
419        else if (options.series) {
420            for (var i=0; i < options.series.length; i++) {
421                if (options.series[i].renderer == $.jqplot.MekkoRenderer) {
422                    setopts = true;
423                }
424            }
425        }
426       
427        if (setopts) {
428            options.axesDefaults.renderer = $.jqplot.MekkoAxisRenderer;
429            options.legend.renderer = $.jqplot.MekkoLegendRenderer;
430            options.legend.preDraw = true;
431        }
432    }
433   
434    $.jqplot.preInitHooks.push(preInit);
435   
436})(jQuery);   
Note: See TracBrowser for help on using the repository browser.