merged cont.
[opensuse:yast-rest-service.git] / webyast / public / javascripts / plugin / jqplot.trendline.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     /**
21      * Class: $.jqplot.Trendline
22      * Plugin which will automatically compute and draw trendlines for plotted data.
23      */
24     $.jqplot.Trendline = function() {
25         // Group: Properties
26         
27         // prop: show
28         // Wether or not to show the trend line.
29         this.show = $.jqplot.config.enablePlugins;
30         // prop: color
31         // CSS color spec for the trend line.
32         // By default this wil be the same color as the primary line.
33         this.color = '#666666';
34         // prop: renderer
35         // Renderer to use to draw the trend line.
36         // The data series that is plotted may not be rendered as a line.
37         // Therefore, we use our own line renderer here to draw a trend line.
38         this.renderer = new $.jqplot.LineRenderer();
39         // prop: rendererOptions
40         // Options to pass to the line renderer.
41         // By default, markers are not shown on trend lines.
42         this.rendererOptions = {marker:{show:false}};
43         // prop: label
44         // Label for the trend line to use in the legend.
45         this.label = '';
46         // prop: type
47         // Either 'exponential', 'exp', or 'linear'.
48         this.type = 'linear';
49         // prop: shadow
50         // true or false, wether or not to show the shadow.
51         this.shadow = true;
52         // prop: markerRenderer
53         // Renderer to use to draw markers on the line.
54         // I think this is wrong.
55         this.markerRenderer = {show:false};
56         // prop: lineWidth
57         // Width of the trend line.
58         this.lineWidth = 1.5;
59         // prop: shadowAngle
60         // Angle of the shadow on the trend line.
61         this.shadowAngle = 45;
62         // prop: shadowOffset
63         // pixel offset for each stroke of the shadow.
64         this.shadowOffset = 1.0;
65         // prop: shadowAlpha
66         // Alpha transparency of the shadow.
67         this.shadowAlpha = 0.07;
68         // prop: shadowDepth
69         // number of strokes to make of the shadow.
70         this.shadowDepth = 3;
71         
72     };
73     
74     $.jqplot.postParseSeriesOptionsHooks.push(parseTrendLineOptions);
75     $.jqplot.postDrawSeriesHooks.push(drawTrendline);
76     $.jqplot.addLegendRowHooks.push(addTrendlineLegend);
77     
78     // called witin scope of the legend object
79     // current series passed in
80     // must return null or an object {label:label, color:color}
81     function addTrendlineLegend(series) {
82         var lt = series.trendline.label.toString();
83         var ret = null;
84         if (this.renderer.constructor != $.jqplot.PieRenderer && series.trendline.show && lt) {
85             ret = {label:lt, color:series.trendline.color};
86         }
87         return ret;
88     }
89
90     // called within scope of a series
91     function parseTrendLineOptions (seriesDefaults, options) {
92         if (this.renderer.constructor != $.jqplot.PieRenderer) {
93             this.trendline = new $.jqplot.Trendline();
94             options = options || {};
95             $.extend(true, this.trendline, {color:this.color}, seriesDefaults.trendline, options.trendline);
96             this.trendline.renderer.init.call(this.trendline, null);
97         }
98     }
99     
100     // called within scope of series object
101     function drawTrendline(sctx, options) {
102         // if we have options, merge trendline options in with precedence
103         options = $.extend(true, {}, this.trendline, options);
104
105         if (options.show && this.renderer.constructor != $.jqplot.PieRenderer) {
106             var fit;
107             // this.renderer.setGridData.call(this);
108             var data = options.data || this.data;
109             fit = fitData(data, this.trendline.type);
110             var gridData = options.gridData || this.renderer.makeGridData.call(this, fit.data);
111         
112             this.trendline.renderer.draw.call(this.trendline, sctx, gridData, {showLine:true, shadow:this.trendline.shadow});
113         }
114     }
115     
116     function regression(x, y, typ)  {
117         var type = (typ == null) ? 'linear' : typ;
118         var N = x.length;
119         var slope;
120         var intercept;  
121         var SX = 0;
122         var SY = 0;
123         var SXX = 0;
124         var SXY = 0;
125         var SYY = 0;
126         var Y = [];
127         var X = [];
128     
129         if (type == 'linear') {
130             X = x;
131             Y = y;
132         }
133         else if (type == 'exp' || type == 'exponential') {
134             for ( var i=0; i<y.length; i++) {
135                 // ignore points <= 0, log undefined.
136                 if (y[i] <= 0) {
137                     N--;
138                 }
139                 else {
140                     X.push(x[i]);
141                     Y.push(Math.log(y[i]));
142                 }
143             }
144         }
145
146         for ( var i = 0; i < N; i++) {
147             SX = SX + X[i];
148             SY = SY + Y[i];
149             SXY = SXY + X[i]* Y[i];
150             SXX = SXX + X[i]* X[i];
151             SYY = SYY + Y[i]* Y[i];
152         }
153
154         slope = (N*SXY - SX*SY)/(N*SXX - SX*SX);
155         intercept = (SY - slope*SX)/N;
156
157         return [slope, intercept];
158     }
159
160     function linearRegression(X,Y) {
161         var ret;
162         ret = regression(X,Y,'linear');
163         return [ret[0],ret[1]];
164     }
165
166     function expRegression(X,Y) {
167         var ret;
168         var x = X;
169         var y = Y;
170         ret = regression(x, y,'exp');
171         var base = Math.exp(ret[0]);
172         var coeff = Math.exp(ret[1]);
173         return [base, coeff];
174     }
175
176     function fitData(data, typ) {
177         var type = (typ == null) ?  'linear' : typ;
178         var ret;
179         var res;
180         var x = [];
181         var y = [];
182         var ypred = [];
183         
184         for (i=0; i<data.length; i++){
185             if (data[i] != null && data[i][0] != null && data[i][1] != null) {
186                 x.push(data[i][0]);
187                 y.push(data[i][1]);
188             }
189         }
190         
191         if (type == 'linear') {
192             ret = linearRegression(x,y);
193             for ( var i=0; i<x.length; i++){
194                 res = ret[0]*x[i] + ret[1];
195                 ypred.push([x[i], res]);
196             }
197         }
198         else if (type == 'exp' || type == 'exponential') {
199             ret = expRegression(x,y);
200             for ( var i=0; i<x.length; i++){
201                 res = ret[1]*Math.pow(ret[0],x[i]);
202                 ypred.push([x[i], res]);
203             }
204         }
205         return {data: ypred, slope: ret[0], intercept: ret[1]};
206     } 
207
208 })(jQuery);