source: firmaeventos/static/plugins/flot/jquery.flot.errorbars.js @ bf47591

Last change on this file since bf47591 was bf47591, checked in by Leonel Hernandez <leonelphm@…>, 7 years ago

Inicializando Proyecto

  • Property mode set to 100644
File size: 12.3 KB
Line 
1/* Flot plugin for plotting error bars.
2
3Copyright (c) 2007-2013 IOLA and Ole Laursen.
4Licensed under the MIT license.
5
6Error bars are used to show standard deviation and other statistical
7properties in a plot.
8
9* Created by Rui Pereira  -  rui (dot) pereira (at) gmail (dot) com
10
11This plugin allows you to plot error-bars over points. Set "errorbars" inside
12the points series to the axis name over which there will be error values in
13your data array (*even* if you do not intend to plot them later, by setting
14"show: null" on xerr/yerr).
15
16The plugin supports these options:
17
18        series: {
19                points: {
20                        errorbars: "x" or "y" or "xy",
21                        xerr: {
22                                show: null/false or true,
23                                asymmetric: null/false or true,
24                                upperCap: null or "-" or function,
25                                lowerCap: null or "-" or function,
26                                color: null or color,
27                                radius: null or number
28                        },
29                        yerr: { same options as xerr }
30                }
31        }
32
33Each data point array is expected to be of the type:
34
35        "x"  [ x, y, xerr ]
36        "y"  [ x, y, yerr ]
37        "xy" [ x, y, xerr, yerr ]
38
39Where xerr becomes xerr_lower,xerr_upper for the asymmetric error case, and
40equivalently for yerr. Eg., a datapoint for the "xy" case with symmetric
41error-bars on X and asymmetric on Y would be:
42
43        [ x, y, xerr, yerr_lower, yerr_upper ]
44
45By default no end caps are drawn. Setting upperCap and/or lowerCap to "-" will
46draw a small cap perpendicular to the error bar. They can also be set to a
47user-defined drawing function, with (ctx, x, y, radius) as parameters, as eg.
48
49        function drawSemiCircle( ctx, x, y, radius ) {
50                ctx.beginPath();
51                ctx.arc( x, y, radius, 0, Math.PI, false );
52                ctx.moveTo( x - radius, y );
53                ctx.lineTo( x + radius, y );
54                ctx.stroke();
55        }
56
57Color and radius both default to the same ones of the points series if not
58set. The independent radius parameter on xerr/yerr is useful for the case when
59we may want to add error-bars to a line, without showing the interconnecting
60points (with radius: 0), and still showing end caps on the error-bars.
61shadowSize and lineWidth are derived as well from the points series.
62
63*/
64
65(function ($) {
66    var options = {
67        series: {
68            points: {
69                errorbars: null, //should be 'x', 'y' or 'xy'
70                xerr: { err: 'x', show: null, asymmetric: null, upperCap: null, lowerCap: null, color: null, radius: null},
71                yerr: { err: 'y', show: null, asymmetric: null, upperCap: null, lowerCap: null, color: null, radius: null}
72            }
73        }
74    };
75
76    function processRawData(plot, series, data, datapoints){
77        if (!series.points.errorbars)
78            return;
79
80        // x,y values
81        var format = [
82            { x: true, number: true, required: true },
83            { y: true, number: true, required: true }
84        ];
85
86        var errors = series.points.errorbars;
87        // error bars - first X then Y
88        if (errors == 'x' || errors == 'xy') {
89            // lower / upper error
90            if (series.points.xerr.asymmetric) {
91                format.push({ x: true, number: true, required: true });
92                format.push({ x: true, number: true, required: true });
93            } else
94                format.push({ x: true, number: true, required: true });
95        }
96        if (errors == 'y' || errors == 'xy') {
97            // lower / upper error
98            if (series.points.yerr.asymmetric) {
99                format.push({ y: true, number: true, required: true });
100                format.push({ y: true, number: true, required: true });
101            } else
102                format.push({ y: true, number: true, required: true });
103        }
104        datapoints.format = format;
105    }
106
107    function parseErrors(series, i){
108
109        var points = series.datapoints.points;
110
111        // read errors from points array
112        var exl = null,
113                exu = null,
114                eyl = null,
115                eyu = null;
116        var xerr = series.points.xerr,
117                yerr = series.points.yerr;
118
119        var eb = series.points.errorbars;
120        // error bars - first X
121        if (eb == 'x' || eb == 'xy') {
122            if (xerr.asymmetric) {
123                exl = points[i + 2];
124                exu = points[i + 3];
125                if (eb == 'xy')
126                    if (yerr.asymmetric){
127                        eyl = points[i + 4];
128                        eyu = points[i + 5];
129                    } else eyl = points[i + 4];
130            } else {
131                exl = points[i + 2];
132                if (eb == 'xy')
133                    if (yerr.asymmetric) {
134                        eyl = points[i + 3];
135                        eyu = points[i + 4];
136                    } else eyl = points[i + 3];
137            }
138        // only Y
139        } else if (eb == 'y')
140            if (yerr.asymmetric) {
141                eyl = points[i + 2];
142                eyu = points[i + 3];
143            } else eyl = points[i + 2];
144
145        // symmetric errors?
146        if (exu == null) exu = exl;
147        if (eyu == null) eyu = eyl;
148
149        var errRanges = [exl, exu, eyl, eyu];
150        // nullify if not showing
151        if (!xerr.show){
152            errRanges[0] = null;
153            errRanges[1] = null;
154        }
155        if (!yerr.show){
156            errRanges[2] = null;
157            errRanges[3] = null;
158        }
159        return errRanges;
160    }
161
162    function drawSeriesErrors(plot, ctx, s){
163
164        var points = s.datapoints.points,
165                ps = s.datapoints.pointsize,
166                ax = [s.xaxis, s.yaxis],
167                radius = s.points.radius,
168                err = [s.points.xerr, s.points.yerr];
169
170        //sanity check, in case some inverted axis hack is applied to flot
171        var invertX = false;
172        if (ax[0].p2c(ax[0].max) < ax[0].p2c(ax[0].min)) {
173            invertX = true;
174            var tmp = err[0].lowerCap;
175            err[0].lowerCap = err[0].upperCap;
176            err[0].upperCap = tmp;
177        }
178
179        var invertY = false;
180        if (ax[1].p2c(ax[1].min) < ax[1].p2c(ax[1].max)) {
181            invertY = true;
182            var tmp = err[1].lowerCap;
183            err[1].lowerCap = err[1].upperCap;
184            err[1].upperCap = tmp;
185        }
186
187        for (var i = 0; i < s.datapoints.points.length; i += ps) {
188
189            //parse
190            var errRanges = parseErrors(s, i);
191
192            //cycle xerr & yerr
193            for (var e = 0; e < err.length; e++){
194
195                var minmax = [ax[e].min, ax[e].max];
196
197                //draw this error?
198                if (errRanges[e * err.length]){
199
200                    //data coordinates
201                    var x = points[i],
202                        y = points[i + 1];
203
204                    //errorbar ranges
205                    var upper = [x, y][e] + errRanges[e * err.length + 1],
206                        lower = [x, y][e] - errRanges[e * err.length];
207
208                    //points outside of the canvas
209                    if (err[e].err == 'x')
210                        if (y > ax[1].max || y < ax[1].min || upper < ax[0].min || lower > ax[0].max)
211                            continue;
212                    if (err[e].err == 'y')
213                        if (x > ax[0].max || x < ax[0].min || upper < ax[1].min || lower > ax[1].max)
214                            continue;
215
216                    // prevent errorbars getting out of the canvas
217                    var drawUpper = true,
218                        drawLower = true;
219
220                    if (upper > minmax[1]) {
221                        drawUpper = false;
222                        upper = minmax[1];
223                    }
224                    if (lower < minmax[0]) {
225                        drawLower = false;
226                        lower = minmax[0];
227                    }
228
229                    //sanity check, in case some inverted axis hack is applied to flot
230                    if ((err[e].err == 'x' && invertX) || (err[e].err == 'y' && invertY)) {
231                        //swap coordinates
232                        var tmp = lower;
233                        lower = upper;
234                        upper = tmp;
235                        tmp = drawLower;
236                        drawLower = drawUpper;
237                        drawUpper = tmp;
238                        tmp = minmax[0];
239                        minmax[0] = minmax[1];
240                        minmax[1] = tmp;
241                    }
242
243                    // convert to pixels
244                    x = ax[0].p2c(x),
245                        y = ax[1].p2c(y),
246                        upper = ax[e].p2c(upper);
247                    lower = ax[e].p2c(lower);
248                    minmax[0] = ax[e].p2c(minmax[0]);
249                    minmax[1] = ax[e].p2c(minmax[1]);
250
251                    //same style as points by default
252                    var lw = err[e].lineWidth ? err[e].lineWidth : s.points.lineWidth,
253                        sw = s.points.shadowSize != null ? s.points.shadowSize : s.shadowSize;
254
255                    //shadow as for points
256                    if (lw > 0 && sw > 0) {
257                        var w = sw / 2;
258                        ctx.lineWidth = w;
259                        ctx.strokeStyle = "rgba(0,0,0,0.1)";
260                        drawError(ctx, err[e], x, y, upper, lower, drawUpper, drawLower, radius, w + w/2, minmax);
261
262                        ctx.strokeStyle = "rgba(0,0,0,0.2)";
263                        drawError(ctx, err[e], x, y, upper, lower, drawUpper, drawLower, radius, w/2, minmax);
264                    }
265
266                    ctx.strokeStyle = err[e].color? err[e].color: s.color;
267                    ctx.lineWidth = lw;
268                    //draw it
269                    drawError(ctx, err[e], x, y, upper, lower, drawUpper, drawLower, radius, 0, minmax);
270                }
271            }
272        }
273    }
274
275    function drawError(ctx,err,x,y,upper,lower,drawUpper,drawLower,radius,offset,minmax){
276
277        //shadow offset
278        y += offset;
279        upper += offset;
280        lower += offset;
281
282        // error bar - avoid plotting over circles
283        if (err.err == 'x'){
284            if (upper > x + radius) drawPath(ctx, [[upper,y],[Math.max(x + radius,minmax[0]),y]]);
285            else drawUpper = false;
286            if (lower < x - radius) drawPath(ctx, [[Math.min(x - radius,minmax[1]),y],[lower,y]] );
287            else drawLower = false;
288        }
289        else {
290            if (upper < y - radius) drawPath(ctx, [[x,upper],[x,Math.min(y - radius,minmax[0])]] );
291            else drawUpper = false;
292            if (lower > y + radius) drawPath(ctx, [[x,Math.max(y + radius,minmax[1])],[x,lower]] );
293            else drawLower = false;
294        }
295
296        //internal radius value in errorbar, allows to plot radius 0 points and still keep proper sized caps
297        //this is a way to get errorbars on lines without visible connecting dots
298        radius = err.radius != null? err.radius: radius;
299
300        // upper cap
301        if (drawUpper) {
302            if (err.upperCap == '-'){
303                if (err.err=='x') drawPath(ctx, [[upper,y - radius],[upper,y + radius]] );
304                else drawPath(ctx, [[x - radius,upper],[x + radius,upper]] );
305            } else if ($.isFunction(err.upperCap)){
306                if (err.err=='x') err.upperCap(ctx, upper, y, radius);
307                else err.upperCap(ctx, x, upper, radius);
308            }
309        }
310        // lower cap
311        if (drawLower) {
312            if (err.lowerCap == '-'){
313                if (err.err=='x') drawPath(ctx, [[lower,y - radius],[lower,y + radius]] );
314                else drawPath(ctx, [[x - radius,lower],[x + radius,lower]] );
315            } else if ($.isFunction(err.lowerCap)){
316                if (err.err=='x') err.lowerCap(ctx, lower, y, radius);
317                else err.lowerCap(ctx, x, lower, radius);
318            }
319        }
320    }
321
322    function drawPath(ctx, pts){
323        ctx.beginPath();
324        ctx.moveTo(pts[0][0], pts[0][1]);
325        for (var p=1; p < pts.length; p++)
326            ctx.lineTo(pts[p][0], pts[p][1]);
327        ctx.stroke();
328    }
329
330    function draw(plot, ctx){
331        var plotOffset = plot.getPlotOffset();
332
333        ctx.save();
334        ctx.translate(plotOffset.left, plotOffset.top);
335        $.each(plot.getData(), function (i, s) {
336            if (s.points.errorbars && (s.points.xerr.show || s.points.yerr.show))
337                drawSeriesErrors(plot, ctx, s);
338        });
339        ctx.restore();
340    }
341
342    function init(plot) {
343        plot.hooks.processRawData.push(processRawData);
344        plot.hooks.draw.push(draw);
345    }
346
347    $.plot.plugins.push({
348                init: init,
349                options: options,
350                name: 'errorbars',
351                version: '1.0'
352            });
353})(jQuery);
Note: See TracBrowser for help on using the repository browser.