Free cookie consent management tool by TermsFeed Policy Generator

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

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

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

File size: 24.9 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    // class: $.jqplot.MekkoAxisRenderer
32    // An axis renderer for a Mekko chart.
33    // Should be used with a Mekko chart where the mekkoRenderer is used on the series.
34    // Displays the Y axis as a range from 0 to 1 (0 to 100%) and the x axis with a tick
35    // for each series scaled to the sum of all the y values.
36    $.jqplot.MekkoAxisRenderer = function() {
37    };
38   
39    // called with scope of axis object.
40    $.jqplot.MekkoAxisRenderer.prototype.init = function(options){
41        // prop: tickMode
42        // How to space the ticks on the axis.
43        // 'bar' will place a tick at the width of each bar. 
44        // This is the default for the x axis.
45        // 'even' will place ticks at even intervals.  This is
46        // the default for x2 axis and y axis.  y axis cannot be changed.
47        this.tickMode;
48        // prop: barLabelRenderer
49        // renderer to use to draw labels under each bar.
50        this.barLabelRenderer = $.jqplot.AxisLabelRenderer;
51        // prop: barLabels
52        // array of labels to put under each bar.
53        this.barLabels = this.barLabels || [];
54        // prop: barLabelOptions
55        // options object to pass to the bar label renderer.
56        this.barLabelOptions = {};
57        this.tickOptions = $.extend(true, {showGridline:false}, this.tickOptions);
58        this._barLabels = [];
59        $.extend(true, this, options);
60        if (this.name == 'yaxis') {
61            this.tickOptions.formatString = this.tickOptions.formatString || "%d\%";
62        }
63        var db = this._dataBounds;
64        db.min = 0;
65        // for y axes, scale always go from 0 to 1 (0 to 100%)
66        if (this.name == 'yaxis' || this.name == 'y2axis') {
67            db.max = 100;
68            this.tickMode = 'even';
69        }
70        // For x axes, scale goes from 0 to sum of all y values.
71        else if (this.name == 'xaxis'){
72            this.tickMode = (this.tickMode == null) ? 'bar' : this.tickMode;
73            for (var i=0; i<this._series.length; i++) {
74                db.max += this._series[i]._sumy;
75            }
76        }
77        else if (this.name == 'x2axis'){
78            this.tickMode = (this.tickMode == null) ? 'even' : this.tickMode;
79            for (var i=0; i<this._series.length; i++) {
80                db.max += this._series[i]._sumy;
81            }
82        }
83    };
84   
85    // called with scope of axis
86    $.jqplot.MekkoAxisRenderer.prototype.draw = function(ctx, plot) {
87        if (this.show) {
88            // populate the axis label and value properties.
89            // createTicks is a method on the renderer, but
90            // call it within the scope of the axis.
91            this.renderer.createTicks.call(this);
92            // fill a div with axes labels in the right direction.
93            // Need to pregenerate each axis to get it's bounds and
94            // position it and the labels correctly on the plot.
95            var dim=0;
96            var temp;
97           
98            var elem = document.createElement('div');
99            this._elem = $(elem);
100            this._elem.addClass('jqplot-axis jqplot-'+this.name);
101            this._elem.css('position', 'absolute');
102            elem = null;
103           
104            if (this.name == 'xaxis' || this.name == 'x2axis') {
105                this._elem.width(this._plotDimensions.width);
106            }
107            else {
108                this._elem.height(this._plotDimensions.height);
109            }
110           
111            // draw the axis label
112            // create a _label object.
113            this.labelOptions.axis = this.name;
114            this._label = new this.labelRenderer(this.labelOptions);
115            if (this._label.show) {
116                this._elem.append(this._label.draw(ctx));
117            }
118           
119            var t, tick, elem;
120            if (this.showTicks) {
121                t = this._ticks;
122                for (var i=0; i<t.length; i++) {
123                    tick = t[i];
124                    if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
125                        this._elem.append(tick.draw(ctx));
126                    }
127                }
128            }
129           
130            // draw the series labels
131            for (i=0; i<this.barLabels.length; i++) {
132                this.barLabelOptions.axis = this.name;
133                this.barLabelOptions.label = this.barLabels[i];
134                this._barLabels.push(new this.barLabelRenderer(this.barLabelOptions));
135                if (this.tickMode != 'bar') {
136                    this._barLabels[i].show = false;
137                }
138                if (this._barLabels[i].show) {
139                    var elem = this._barLabels[i].draw(ctx, plot);
140                    elem.removeClass('jqplot-'+this.name+'-label');
141                    elem.addClass('jqplot-'+this.name+'-tick');
142                    elem.addClass('jqplot-mekko-barLabel');
143                    elem.appendTo(this._elem);
144                    elem = null;
145                }   
146            }
147           
148        }
149        return this._elem;
150    };
151   
152    // called with scope of an axis
153    $.jqplot.MekkoAxisRenderer.prototype.reset = function() {
154        this.min = this._min;
155        this.max = this._max;
156        this.tickInterval = this._tickInterval;
157        this.numberTicks = this._numberTicks;
158        // this._ticks = this.__ticks;
159    };
160   
161    // called with scope of axis
162    $.jqplot.MekkoAxisRenderer.prototype.set = function() {
163        var dim = 0;
164        var temp;
165        var w = 0;
166        var h = 0;
167        var lshow = (this._label == null) ? false : this._label.show;
168        if (this.show && this.showTicks) {
169            var t = this._ticks;
170            for (var i=0; i<t.length; i++) {
171                var tick = t[i];
172                if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
173                    if (this.name == 'xaxis' || this.name == 'x2axis') {
174                        temp = tick._elem.outerHeight(true);
175                    }
176                    else {
177                        temp = tick._elem.outerWidth(true);
178                    }
179                    if (temp > dim) {
180                        dim = temp;
181                    }
182                }
183            }
184           
185            if (lshow) {
186                w = this._label._elem.outerWidth(true);
187                h = this._label._elem.outerHeight(true);
188            }
189            if (this.name == 'xaxis') {
190                dim = dim + h;
191                this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'});
192            }
193            else if (this.name == 'x2axis') {
194                dim = dim + h;
195                this._elem.css({'height':dim+'px', left:'0px', top:'0px'});
196            }
197            else if (this.name == 'yaxis') {
198                dim = dim + w;
199                this._elem.css({'width':dim+'px', left:'0px', top:'0px'});
200                if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
201                    this._label._elem.css('width', w+'px');
202                }
203            }
204            else {
205                dim = dim + w;
206                this._elem.css({'width':dim+'px', right:'0px', top:'0px'});
207                if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
208                    this._label._elem.css('width', w+'px');
209                }
210            }
211        } 
212    };   
213   
214    // called with scope of axis
215    $.jqplot.MekkoAxisRenderer.prototype.createTicks = function() {
216        // we're are operating on an axis here
217        var ticks = this._ticks;
218        var userTicks = this.ticks;
219        var name = this.name;
220        // databounds were set on axis initialization.
221        var db = this._dataBounds;
222        var dim, interval;
223        var min, max;
224        var pos1, pos2;
225        var t, tt, i, j;
226       
227        // if we already have ticks, use them.
228        // ticks must be in order of increasing value.
229       
230        if (userTicks.length) {
231            // ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed
232            for (i=0; i<userTicks.length; i++){
233                var ut = userTicks[i];
234                var t = new this.tickRenderer(this.tickOptions);
235                if (ut.constructor == Array) {
236                    t.value = ut[0];
237                    t.label = ut[1];
238                    if (!this.showTicks) {
239                        t.showLabel = false;
240                        t.showMark = false;
241                    }
242                    else if (!this.showTickMarks) {
243                        t.showMark = false;
244                    }
245                    t.setTick(ut[0], this.name);
246                    this._ticks.push(t);
247                }
248               
249                else {
250                    t.value = ut;
251                    if (!this.showTicks) {
252                        t.showLabel = false;
253                        t.showMark = false;
254                    }
255                    else if (!this.showTickMarks) {
256                        t.showMark = false;
257                    }
258                    t.setTick(ut, this.name);
259                    this._ticks.push(t);
260                }
261            }
262            this.numberTicks = userTicks.length;
263            this.min = this._ticks[0].value;
264            this.max = this._ticks[this.numberTicks-1].value;
265            this.tickInterval = (this.max - this.min) / (this.numberTicks - 1);
266        }
267       
268        // we don't have any ticks yet, let's make some!
269        else {
270            if (name == 'xaxis' || name == 'x2axis') {
271                dim = this._plotDimensions.width;
272            }
273            else {
274                dim = this._plotDimensions.height;
275            }
276           
277            // if min, max and number of ticks specified, user can't specify interval.
278            if (this.min != null && this.max != null && this.numberTicks != null) {
279                this.tickInterval = null;
280            }
281       
282            min = (this.min != null) ? this.min : db.min;
283            max = (this.max != null) ? this.max : db.max;
284           
285            // if min and max are same, space them out a bit.+
286            if (min == max) {
287                var adj = 0.05;
288                if (min > 0) {
289                    adj = Math.max(Math.log(min)/Math.LN10, 0.05);
290                }
291                min -= adj;
292                max += adj;
293            }
294
295            var range = max - min;
296            var rmin, rmax;
297            var temp, prev, curr;
298            var ynumticks = [3,5,6,11,21];
299           
300            // yaxis divide ticks in nice intervals from 0 to 1.
301            if (this.name == 'yaxis' || this.name == 'y2axis') {
302                this.min = 0;
303                this.max = 100;
304                // user didn't specify number of ticks.
305                if (!this.numberTicks){
306                    if (this.tickInterval) {
307                        this.numberTicks = 3 + Math.ceil(range / this.tickInterval);
308                    }
309                    else {
310                        temp = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing);
311                        for (i=0; i<ynumticks.length; i++) {
312                            curr = temp/ynumticks[i];
313                            if (curr == 1) {
314                                this.numberTicks = ynumticks[i];
315                                break;
316                            }
317                            else if (curr > 1) {
318                                prev = curr;
319                                continue;
320                            }
321                            else if (curr < 1) {
322                                // was prev or is curr closer to one?
323                                if (Math.abs(prev - 1) < Math.abs(curr - 1)) {
324                                    this.numberTicks = ynumticks[i-1];
325                                    break;
326                                }
327                                else {
328                                    this.numberTicks = ynumticks[i];
329                                    break;
330                                }
331                            }
332                            else if (i == ynumticks.length -1) {
333                                this.numberTicks = ynumticks[i];
334                            }
335                        }
336                        this.tickInterval = range / (this.numberTicks - 1);
337                    }
338                }
339               
340                // user did specify number of ticks.
341                else {
342                    this.tickInterval = range / (this.numberTicks - 1);
343                }
344
345                for (var i=0; i<this.numberTicks; i++){
346                    tt = this.min + i * this.tickInterval;
347                    t = new this.tickRenderer(this.tickOptions);
348                    // var t = new $.jqplot.AxisTickRenderer(this.tickOptions);
349                    if (!this.showTicks) {
350                        t.showLabel = false;
351                        t.showMark = false;
352                    }
353                    else if (!this.showTickMarks) {
354                        t.showMark = false;
355                    }
356                    t.setTick(tt, this.name);
357                    this._ticks.push(t);
358                }
359            }
360           
361            // for x axes, have number ot ticks equal to number of series and ticks placed
362            // at sum of y values for each series.
363            else if (this.tickMode == 'bar') {
364                this.min = 0;
365                this.numberTicks = this._series.length + 1;
366                t = new this.tickRenderer(this.tickOptions);
367                if (!this.showTicks) {
368                    t.showLabel = false;
369                    t.showMark = false;
370                }
371                else if (!this.showTickMarks) {
372                    t.showMark = false;
373                }
374                t.setTick(0, this.name);
375                this._ticks.push(t);
376               
377                temp = 0;
378
379                for (i=1; i<this.numberTicks; i++){
380                    temp += this._series[i-1]._sumy;
381                    t = new this.tickRenderer(this.tickOptions);
382                    if (!this.showTicks) {
383                        t.showLabel = false;
384                        t.showMark = false;
385                    }
386                    else if (!this.showTickMarks) {
387                        t.showMark = false;
388                    }
389                    t.setTick(temp, this.name);
390                    this._ticks.push(t);
391                }
392                this.max = this.max || temp;
393               
394                // if user specified a max and it is greater than sum, add a tick
395                if (this.max > temp) {
396                     t = new this.tickRenderer(this.tickOptions);
397                    if (!this.showTicks) {
398                        t.showLabel = false;
399                        t.showMark = false;
400                    }
401                    else if (!this.showTickMarks) {
402                        t.showMark = false;
403                    }
404                    t.setTick(this.max, this.name);
405                    this._ticks.push(t);
406                   
407                }
408            }
409           
410            else if (this.tickMode == 'even') {
411                this.min = 0;
412                this.max = this.max || db.max;
413                // get a desired number of ticks
414                var nt = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing);
415                range = this.max - this.min;
416                this.numberTicks = nt;
417                this.tickInterval = range / (this.numberTicks - 1);
418
419                for (i=0; i<this.numberTicks; i++){
420                    tt = this.min + i * this.tickInterval;
421                    t = new this.tickRenderer(this.tickOptions);
422                    // var t = new $.jqplot.AxisTickRenderer(this.tickOptions);
423                    if (!this.showTicks) {
424                        t.showLabel = false;
425                        t.showMark = false;
426                    }
427                    else if (!this.showTickMarks) {
428                        t.showMark = false;
429                    }
430                    t.setTick(tt, this.name);
431                    this._ticks.push(t);
432                }
433               
434            }
435        }
436    };
437   
438    // called with scope of axis
439    $.jqplot.MekkoAxisRenderer.prototype.pack = function(pos, offsets) {
440        var ticks = this._ticks;
441        var max = this.max;
442        var min = this.min;
443        var offmax = offsets.max;
444        var offmin = offsets.min;
445        var lshow = (this._label == null) ? false : this._label.show;
446       
447        for (var p in pos) {
448            this._elem.css(p, pos[p]);
449        }
450       
451        this._offsets = offsets;
452        // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left.
453        var pixellength = offmax - offmin;
454        var unitlength = max - min;
455       
456        // point to unit and unit to point conversions references to Plot DOM element top left corner.
457        this.p2u = function(p){
458            return (p - offmin) * unitlength / pixellength + min;
459        };
460       
461        this.u2p = function(u){
462            return (u - min) * pixellength / unitlength + offmin;
463        };
464               
465        if (this.name == 'xaxis' || this.name == 'x2axis'){
466            this.series_u2p = function(u){
467                return (u - min) * pixellength / unitlength;
468            };
469            this.series_p2u = function(p){
470                return p * unitlength / pixellength + min;
471            };
472        }
473       
474        else {
475            this.series_u2p = function(u){
476                return (u - max) * pixellength / unitlength;
477            };
478            this.series_p2u = function(p){
479                return p * unitlength / pixellength + max;
480            };
481        }
482       
483        if (this.show) {
484            if (this.name == 'xaxis' || this.name == 'x2axis') {
485                for (var i=0; i<ticks.length; i++) {
486                    var t = ticks[i];
487                    if (t.show && t.showLabel) {
488                        var shim;
489                       
490                        if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
491                            // will need to adjust auto positioning based on which axis this is.
492                            var temp = (this.name == 'xaxis') ? 1 : -1;
493                            switch (t.labelPosition) {
494                                case 'auto':
495                                    // position at end
496                                    if (temp * t.angle < 0) {
497                                        shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
498                                    }
499                                    // position at start
500                                    else {
501                                        shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
502                                    }
503                                    break;
504                                case 'end':
505                                    shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
506                                    break;
507                                case 'start':
508                                    shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
509                                    break;
510                                case 'middle':
511                                    shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
512                                    break;
513                                default:
514                                    shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
515                                    break;
516                            }
517                        }
518                        else {
519                            shim = -t.getWidth()/2;
520                        }
521                        var val = this.u2p(t.value) + shim + 'px';
522                        t._elem.css('left', val);
523                        t.pack();
524                    }
525                }
526                var w;
527                if (lshow) {
528                    w = this._label._elem.outerWidth(true);
529                    this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px');
530                    if (this.name == 'xaxis') {
531                        this._label._elem.css('bottom', '0px');
532                    }
533                    else {
534                        this._label._elem.css('top', '0px');
535                    }
536                    this._label.pack();
537                }
538                // now show the labels under the bars.
539                var b, l, r;
540                for (var i=0; i<this.barLabels.length; i++) {
541                    b = this._barLabels[i];
542                    if (b.show) {
543                        w = b.getWidth();
544                        l = this._ticks[i].getLeft() + this._ticks[i].getWidth();
545                        r = this._ticks[i+1].getLeft();
546                        b._elem.css('left', (r+l-w)/2+'px');
547                        b._elem.css('top', this._ticks[i]._elem.css('top'));
548                        b.pack();
549                    }
550                }
551            }
552            else {
553                for (var i=0; i<ticks.length; i++) {
554                    var t = ticks[i];
555                    if (t.show && t.showLabel) {                       
556                        var shim;
557                        if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
558                            // will need to adjust auto positioning based on which axis this is.
559                            var temp = (this.name == 'yaxis') ? 1 : -1;
560                            switch (t.labelPosition) {
561                                case 'auto':
562                                    // position at end
563                                case 'end':
564                                    if (temp * t.angle < 0) {
565                                        shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
566                                    }
567                                    else {
568                                        shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
569                                    }
570                                    break;
571                                case 'start':
572                                    if (t.angle > 0) {
573                                        shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
574                                    }
575                                    else {
576                                        shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
577                                    }
578                                    break;
579                                case 'middle':
580                                    shim = -t.getHeight()/2;
581                                    break;
582                                default:
583                                    shim = -t.getHeight()/2;
584                                    break;
585                            }
586                        }
587                        else {
588                            shim = -t.getHeight()/2;
589                        }
590                       
591                        var val = this.u2p(t.value) + shim + 'px';
592                        t._elem.css('top', val);
593                        t.pack();
594                    }
595                }
596                if (lshow) {
597                    var h = this._label._elem.outerHeight(true);
598                    this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px');
599                    if (this.name == 'yaxis') {
600                        this._label._elem.css('left', '0px');
601                    }
602                    else {
603                        this._label._elem.css('right', '0px');
604                    }   
605                    this._label.pack();
606                }
607            }
608        }
609    };
610})(jQuery);
Note: See TracBrowser for help on using the repository browser.