merged cont.
[opensuse:yast-rest-service.git] / webservice / public / javascripts / plugin / jqplot.barRenderer.js
1 /**
2  * Copyright (c) 2009 Chris Leonello
3  * jqPlot is currently available for use in all personal or commercial projects 
4  * under both the MIT and GPL version 2.0 licenses. This means that you can 
5  * choose the license that best suits your project and use it accordingly. 
6  *
7  * The author would appreciate an email letting him know of any substantial
8  * use of jqPlot.  You can reach the author at: chris dot leonello at gmail 
9  * dot com or see http://www.jqplot.com/info.php .  This is, of course, 
10  * not required.
11  *
12  * If you are feeling kind and generous, consider supporting the project by
13  * making a donation at: http://www.jqplot.com/donate.php .
14  *
15  * Thanks for using jqPlot!
16  * 
17  */
18 (function($) {
19     
20     // Class: $.jqplot.BarRenderer
21     // A plugin renderer for jqPlot to draw a bar plot.
22     // Draws series as a line.
23     
24     $.jqplot.BarRenderer = function(){
25         $.jqplot.LineRenderer.call(this);
26     };
27     
28     $.jqplot.BarRenderer.prototype = new $.jqplot.LineRenderer();
29     $.jqplot.BarRenderer.prototype.constructor = $.jqplot.BarRenderer;
30     
31     // called with scope of series.
32     $.jqplot.BarRenderer.prototype.init = function(options) {
33         // Group: Properties
34         //
35         // prop: barPadding
36         // Number of pixels between adjacent bars at the same axis value.
37         this.barPadding = 8;
38         // prop: barMargin
39         // Number of pixels between groups of bars at adjacent axis values.
40         this.barMargin = 10;
41         // prop: barDirection
42         // 'vertical' = up and down bars, 'horizontal' = side to side bars
43         this.barDirection = 'vertical';
44         // prop: barWidth
45         // Width of the bar in pixels (auto by devaul).  null = calculated automatically.
46         this.barWidth = null;
47         // prop: shadowOffset
48         // offset of the shadow from the slice and offset of 
49         // each succesive stroke of the shadow from the last.
50         this.shadowOffset = 2;
51         // prop: shadowDepth
52         // number of strokes to apply to the shadow, 
53         // each stroke offset shadowOffset from the last.
54         this.shadowDepth = 5;
55         // prop: shadowAlpha
56         // transparency of the shadow (0 = transparent, 1 = opaque)
57         this.shadowAlpha = 0.08;
58         // prop: waterfall
59         // true to enable waterfall plot.
60         this.waterfall = false;
61         // prop: varyBarColor
62         // true to color each bar separately.
63         this.varyBarColor = false;
64         $.extend(true, this, options);
65         // fill is still needed to properly draw the legend.
66         // bars have to be filled.
67         this.fill = true;
68         
69         if (this.waterfall) {
70             this.fillToZero = false;
71             this.disableStack = true;
72         }
73         
74         if (this.barDirection == 'vertical' ) {
75             this._primaryAxis = '_xaxis';
76             this._stackAxis = 'y';
77             this.fillAxis = 'y';
78         }
79         else {
80             this._primaryAxis = '_yaxis';
81             this._stackAxis = 'x';
82             this.fillAxis = 'x';
83         }
84         // set the shape renderer options
85         var opts = {lineJoin:'miter', lineCap:'round', fill:true, isarc:false, strokeStyle:this.color, fillStyle:this.color, closePath:this.fill};
86         this.renderer.shapeRenderer.init(opts);
87         // set the shadow renderer options
88         var sopts = {lineJoin:'miter', lineCap:'round', fill:true, isarc:false, angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, depth:this.shadowDepth, closePath:this.fill};
89         this.renderer.shadowRenderer.init(sopts);
90     };
91     
92     // called with scope of series
93     function barPreInit(target, data, seriesDefaults, options) {
94         if (this.rendererOptions.barDirection == 'horizontal') {
95             this._stackAxis = 'x';
96             this._primaryAxis = '_yaxis';
97         }
98         if (this.rendererOptions.waterfall == true) {
99             this._data = $.extend(true, [], this.data);
100             var sum = 0;
101             var pos = (!this.rendererOptions.barDirection || this.rendererOptions.barDirection == 'vertical') ? 1 : 0;
102             for(var i=0; i<this.data.length; i++) {
103                 sum += this.data[i][pos];
104                 if (i>0) {
105                     this.data[i][pos] += this.data[i-1][pos];
106                 }
107             }
108             this.data[this.data.length] = (pos == 1) ? [this.data.length+1, sum] : [sum, this.data.length+1];
109             this._data[this._data.length] = (pos == 1) ? [this._data.length+1, sum] : [sum, this._data.length+1];
110         }
111     }
112     
113     $.jqplot.preSeriesInitHooks.push(barPreInit);
114     
115     // needs to be called with scope of series, not renderer.
116     $.jqplot.BarRenderer.prototype.calcSeriesNumbers = function() {
117         var nvals = 0;
118         var nseries = 0;
119         var paxis = this[this._primaryAxis];
120         var s, series, pos;
121         // loop through all series on this axis
122         for (var i=0; i < paxis._series.length; i++) {
123             series = paxis._series[i];
124             if (series === this) {
125                 pos = i;
126             }
127             // is the series rendered as a bar?
128             if (series.renderer.constructor == $.jqplot.BarRenderer) {
129                 // gridData may not be computed yet, use data length insted
130                 nvals += series.data.length;
131                 nseries += 1;
132             }
133         }
134         return [nvals, nseries, pos];
135     };
136
137     $.jqplot.BarRenderer.prototype.setBarWidth = function() {
138         // need to know how many data values we have on the approprate axis and figure it out.
139         var i;
140         var nvals = 0;
141         var nseries = 0;
142         var paxis = this[this._primaryAxis];
143         var s, series, pos;
144         var temp = this.renderer.calcSeriesNumbers.call(this);
145         nvals = temp[0];
146         nseries = temp[1];
147         var nticks = paxis.numberTicks;
148         var nbins = (nticks-1)/2;
149         // so, now we have total number of axis values.
150         if (paxis.name == 'xaxis' || paxis.name == 'x2axis') {
151             if (this._stack) {
152                 this.barWidth = (paxis._offsets.max - paxis._offsets.min) / nvals * nseries - this.barMargin;
153             }
154             else {
155                 this.barWidth = ((paxis._offsets.max - paxis._offsets.min)/nbins  - this.barPadding * (nseries-1) - this.barMargin*2)/nseries;
156                 // this.barWidth = (paxis._offsets.max - paxis._offsets.min) / nvals - this.barPadding - this.barMargin/nseries;
157             }
158         }
159         else {
160             if (this._stack) {
161                 this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals * nseries - this.barMargin;
162             }
163             else {
164                 this.barWidth = ((paxis._offsets.min - paxis._offsets.max)/nbins  - this.barPadding * (nseries-1) - this.barMargin*2)/nseries;
165                 // this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals - this.barPadding - this.barMargin/nseries;
166             }
167         }
168         return [nvals, nseries];
169     };
170     
171     $.jqplot.BarRenderer.prototype.draw = function(ctx, gridData, options) {
172         var i;
173         var opts = (options != undefined) ? options : {};
174         var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
175         var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
176         var fill = (opts.fill != undefined) ? opts.fill : this.fill;
177         var xaxis = this.xaxis;
178         var yaxis = this.yaxis;
179         var xp = this._xaxis.series_u2p;
180         var yp = this._yaxis.series_u2p;
181         var pointx, pointy, nvals, nseries, pos;
182         
183         if (this.barWidth == null) {
184             this.renderer.setBarWidth.call(this);
185         }
186         
187         var temp = this.renderer.calcSeriesNumbers.call(this);
188         nvals = temp[0];
189         nseries = temp[1];
190         pos = temp[2];
191         
192         if (this._stack) {
193             this._barNudge = 0;
194         }
195         else {
196             this._barNudge = (-Math.abs(nseries/2 - 0.5) + pos) * (this.barWidth + this.barPadding);
197         }
198         if (showLine) {
199             var negativeColors = new $.jqplot.ColorGenerator(this.negativeSeriesColors);
200             var positiveColors = new $.jqplot.ColorGenerator(this.seriesColors);
201             var negativeColor = negativeColors.get(this.index);
202             if (! this.useNegativeColors) {
203                 negativeColor = opts.fillStyle;
204             }
205             var positiveColor = opts.fillStyle;
206             
207             if (this.barDirection == 'vertical') {
208                 for (var i=0; i<gridData.length; i++) {
209                     points = [];
210                     var base = gridData[i][0] + this._barNudge;
211                     var ystart;
212                     
213                     // stacked
214                     if (this._stack && this._prevGridData.length) {
215                         ystart = this._prevGridData[i][1];
216                     }
217                     // not stacked and first series in stack
218                     else {
219                         if (this.fillToZero) {
220                             ystart = this._yaxis.series_u2p(0);
221                         }
222                         else if (this.waterfall && i > 0 && i < this.gridData.length-1) {
223                             ystart = this.gridData[i-1][1];
224                         }
225                         else {
226                             ystart = ctx.canvas.height;
227                         }
228                     }
229                     if ((this.fillToZero && this._plotData[i][1] < 0) || (this.waterfall && this._data[i][1] < 0)) {
230                         if (this.varyBarColor) {
231                             if (this.useNegativeColors) {
232                                 opts.fillStyle = negativeColors.next();
233                             }
234                             else {
235                                 opts.fillStyle = positiveColors.next();
236                             }
237                         }
238                         else {
239                             opts.fillStyle = negativeColor;
240                         }
241                     }
242                     else {
243                         if (this.varyBarColor) {
244                             opts.fillStyle = positiveColors.next();
245                         }
246                         else {
247                             opts.fillStyle = positiveColor;
248                         }
249                     }
250                     
251                     points.push([base-this.barWidth/2, ystart]);
252                     points.push([base-this.barWidth/2, gridData[i][1]]);
253                     points.push([base+this.barWidth/2, gridData[i][1]]);
254                     points.push([base+this.barWidth/2, ystart]);
255                     // now draw the shadows if not stacked.
256                     // for stacked plots, they are predrawn by drawShadow
257                     if (shadow && !this._stack) {
258                         this.renderer.shadowRenderer.draw(ctx, points, opts);
259                     }
260                     this.renderer.shapeRenderer.draw(ctx, points, opts); 
261                 }
262             }
263             
264             else if (this.barDirection == 'horizontal'){
265                 for (var i=0; i<gridData.length; i++) {
266                     points = [];
267                     var base = gridData[i][1] - this._barNudge;
268                     var xstart;
269                     
270                     if (this._stack && this._prevGridData.length) {
271                         xstart = this._prevGridData[i][0];
272                     }
273                     // not stacked and first series in stack
274                     else {
275                         if (this.fillToZero) {
276                             xstart = this._xaxis.series_u2p(0);
277                         }
278                         else if (this.waterfall && i > 0 && i < this.gridData.length-1) {
279                             xstart = this.gridData[i-1][1];
280                         }
281                         else {
282                             xstart = 0;
283                         }
284                     }
285                     if ((this.fillToZero && this._plotData[i][1] < 0) || (this.waterfall && this._data[i][1] < 0)) {
286                         if (this.varyBarColor) {
287                             if (this.useNegativeColors) {
288                                 opts.fillStyle = negativeColors.next();
289                             }
290                             else {
291                                 opts.fillStyle = positiveColors.next();
292                             }
293                         }
294                     }
295                     else {
296                         if (this.varyBarColor) {
297                             opts.fillStyle = positiveColors.next();
298                         }
299                         else {
300                             opts.fillStyle = positiveColor;
301                         }                    
302                     }
303                     
304                     points.push([xstart, base+this.barWidth/2]);
305                     points.push([gridData[i][0], base+this.barWidth/2]);
306                     points.push([gridData[i][0], base-this.barWidth/2]);
307                     points.push([xstart, base-this.barWidth/2]);
308                     // now draw the shadows if not stacked.
309                     // for stacked plots, they are predrawn by drawShadow
310                     if (shadow && !this._stack) {
311                         this.renderer.shadowRenderer.draw(ctx, points, opts);
312                     }
313                     this.renderer.shapeRenderer.draw(ctx, points, opts); 
314                 }  
315             }
316         }                
317
318     };
319     
320      
321     // for stacked plots, shadows will be pre drawn by drawShadow.
322     $.jqplot.BarRenderer.prototype.drawShadow = function(ctx, gridData, options) {
323         var i;
324         var opts = (options != undefined) ? options : {};
325         var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
326         var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
327         var fill = (opts.fill != undefined) ? opts.fill : this.fill;
328         var xaxis = this.xaxis;
329         var yaxis = this.yaxis;
330         var xp = this._xaxis.series_u2p;
331         var yp = this._yaxis.series_u2p;
332         var pointx, pointy, nvals, nseries, pos;
333         
334         if (this._stack && this.shadow) {
335             if (this.barWidth == null) {
336                 this.renderer.setBarWidth.call(this);
337             }
338         
339             var temp = this.renderer.calcSeriesNumbers.call(this);
340             nvals = temp[0];
341             nseries = temp[1];
342             pos = temp[2];
343         
344             if (this._stack) {
345                 this._barNudge = 0;
346             }
347             else {
348                 this._barNudge = (-Math.abs(nseries/2 - 0.5) + pos) * (this.barWidth + this.barPadding);
349             }
350             if (showLine) {
351             
352                 if (this.barDirection == 'vertical') {
353                     for (var i=0; i<gridData.length; i++) {
354                         points = [];
355                         var base = gridData[i][0] + this._barNudge;
356                         var ystart;
357                     
358                         if (this._stack && this._prevGridData.length) {
359                             ystart = this._prevGridData[i][1];
360                         }
361                         else {
362                             if (this.fillToZero) {
363                                 ystart = this._yaxis.series_u2p(0);
364                             }
365                             else {
366                                 ystart = ctx.canvas.height;
367                             }
368                         }
369                     
370                         points.push([base-this.barWidth/2, ystart]);
371                         points.push([base-this.barWidth/2, gridData[i][1]]);
372                         points.push([base+this.barWidth/2, gridData[i][1]]);
373                         points.push([base+this.barWidth/2, ystart]);
374                         this.renderer.shadowRenderer.draw(ctx, points, opts);
375                     }
376                 }
377             
378                 else if (this.barDirection == 'horizontal'){
379                     for (var i=0; i<gridData.length; i++) {
380                         points = [];
381                         var base = gridData[i][1] - this._barNudge;
382                         var xstart;
383                     
384                         if (this._stack && this._prevGridData.length) {
385                             xstart = this._prevGridData[i][0];
386                         }
387                         else {
388                             xstart = 0;
389                         }
390                     
391                         points.push([xstart, base+this.barWidth/2]);
392                         points.push([gridData[i][0], base+this.barWidth/2]);
393                         points.push([gridData[i][0], base-this.barWidth/2]);
394                         points.push([xstart, base-this.barWidth/2]);
395                         this.renderer.shadowRenderer.draw(ctx, points, opts);
396                     }  
397                 }
398             }   
399             
400         }
401                      
402
403     };
404 })(jQuery);