Subversion Repositories Integrator Subversion

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 espaco 1
/* Flot plugin for computing bottoms for filled line and bar charts.
2
 
3
Copyright (c) 2007-2014 IOLA and Ole Laursen.
4
Licensed under the MIT license.
5
 
6
The case: you've got two series that you want to fill the area between. In Flot
7
terms, you need to use one as the fill bottom of the other. You can specify the
8
bottom of each data point as the third coordinate manually, or you can use this
9
plugin to compute it for you.
10
 
11
In order to name the other series, you need to give it an id, like this:
12
 
13
        var dataset = [
14
                { data: [ ... ], id: "foo" } ,         // use default bottom
15
                { data: [ ... ], fillBetween: "foo" }, // use first dataset as bottom
16
        ];
17
 
18
        $.plot($("#placeholder"), dataset, { lines: { show: true, fill: true }});
19
 
20
As a convenience, if the id given is a number that doesn't appear as an id in
21
the series, it is interpreted as the index in the array instead (so fillBetween:
22
 
23
 
24
Internally, the plugin modifies the datapoints in each series. For line series,
25
extra data points might be inserted through interpolation. Note that at points
26
where the bottom line is not defined (due to a null point or start/end of line),
27
the current line will show a gap too. The algorithm comes from the
28
jquery.flot.stack.js plugin, possibly some code could be shared.
29
 
30
*/
31
 
32
(function ( $ ) {
33
 
34
        var options = {
35
                series: {
36
                        fillBetween: null       // or number
37
                }
38
        };
39
 
40
        function init( plot ) {
41
 
42
                function findBottomSeries( s, allseries ) {
43
 
44
                        var i;
45
 
46
                        for ( i = 0; i < allseries.length; ++i ) {
47
                                if ( allseries[ i ].id === s.fillBetween ) {
48
                                        return allseries[ i ];
49
                                }
50
                        }
51
 
52
                        if ( typeof s.fillBetween === "number" ) {
53
                                if ( s.fillBetween < 0 || s.fillBetween >= allseries.length ) {
54
                                        return null;
55
                                }
56
                                return allseries[ s.fillBetween ];
57
                        }
58
 
59
                        return null;
60
                }
61
 
62
                function computeFillBottoms( plot, s, datapoints ) {
63
 
64
                        if ( s.fillBetween == null ) {
65
                                return;
66
                        }
67
 
68
                        var other = findBottomSeries( s, plot.getData() );
69
 
70
                        if ( !other ) {
71
                                return;
72
                        }
73
 
74
                        var ps = datapoints.pointsize,
75
                                points = datapoints.points,
76
                                otherps = other.datapoints.pointsize,
77
                                otherpoints = other.datapoints.points,
78
                                newpoints = [],
79
                                px, py, intery, qx, qy, bottom,
80
                                withlines = s.lines.show,
81
                                withbottom = ps > 2 && datapoints.format[2].y,
82
                                withsteps = withlines && s.lines.steps,
83
                                fromgap = true,
84
                                i = 0,
85
                                j = 0,
86
                                l, m;
87
 
88
                        while ( true ) {
89
 
90
                                if ( i >= points.length ) {
91
                                        break;
92
                                }
93
 
94
                                l = newpoints.length;
95
 
96
                                if ( points[ i ] == null ) {
97
 
98
                                        // copy gaps
99
 
100
                                        for ( m = 0; m < ps; ++m ) {
101
                                                newpoints.push( points[ i + m ] );
102
                                        }
103
 
104
                                        i += ps;
105
 
106
                                } else if ( j >= otherpoints.length ) {
107
 
108
                                        // for lines, we can't use the rest of the points
109
 
110
                                        if ( !withlines ) {
111
                                                for ( m = 0; m < ps; ++m ) {
112
                                                        newpoints.push( points[ i + m ] );
113
                                                }
114
                                        }
115
 
116
                                        i += ps;
117
 
118
                                } else if ( otherpoints[ j ] == null ) {
119
 
120
                                        // oops, got a gap
121
 
122
                                        for ( m = 0; m < ps; ++m ) {
123
                                                newpoints.push( null );
124
                                        }
125
 
126
                                        fromgap = true;
127
                                        j += otherps;
128
 
129
                                } else {
130
 
131
                                        // cases where we actually got two points
132
 
133
                                        px = points[ i ];
134
                                        py = points[ i + 1 ];
135
                                        qx = otherpoints[ j ];
136
                                        qy = otherpoints[ j + 1 ];
137
                                        bottom = 0;
138
 
139
                                        if ( px === qx ) {
140
 
141
                                                for ( m = 0; m < ps; ++m ) {
142
                                                        newpoints.push( points[ i + m ] );
143
                                                }
144
 
145
                                                //newpoints[ l + 1 ] += qy;
146
                                                bottom = qy;
147
 
148
                                                i += ps;
149
                                                j += otherps;
150
 
151
                                        } else if ( px > qx ) {
152
 
153
                                                // we got past point below, might need to
154
                                                // insert interpolated extra point
155
 
156
                                                if ( withlines && i > 0 && points[ i - ps ] != null ) {
157
                                                        intery = py + ( points[ i - ps + 1 ] - py ) * ( qx - px ) / ( points[ i - ps ] - px );
158
                                                        newpoints.push( qx );
159
                                                        newpoints.push( intery );
160
                                                        for ( m = 2; m < ps; ++m ) {
161
                                                                newpoints.push( points[ i + m ] );
162
                                                        }
163
                                                        bottom = qy;
164
                                                }
165
 
166
                                                j += otherps;
167
 
168
                                        } else { // px < qx
169
 
170
                                                // if we come from a gap, we just skip this point
171
 
172
                                                if ( fromgap && withlines ) {
173
                                                        i += ps;
174
                                                        continue;
175
                                                }
176
 
177
                                                for ( m = 0; m < ps; ++m ) {
178
                                                        newpoints.push( points[ i + m ] );
179
                                                }
180
 
181
                                                // we might be able to interpolate a point below,
182
                                                // this can give us a better y
183
 
184
                                                if ( withlines && j > 0 && otherpoints[ j - otherps ] != null ) {
185
                                                        bottom = qy + ( otherpoints[ j - otherps + 1 ] - qy ) * ( px - qx ) / ( otherpoints[ j - otherps ] - qx );
186
                                                }
187
 
188
                                                //newpoints[l + 1] += bottom;
189
 
190
                                                i += ps;
191
                                        }
192
 
193
                                        fromgap = false;
194
 
195
                                        if ( l !== newpoints.length && withbottom ) {
196
                                                newpoints[ l + 2 ] = bottom;
197
                                        }
198
                                }
199
 
200
                                // maintain the line steps invariant
201
 
202
                                if ( withsteps && l !== newpoints.length && l > 0 &&
203
                                        newpoints[ l ] !== null &&
204
                                        newpoints[ l ] !== newpoints[ l - ps ] &&
205
                                        newpoints[ l + 1 ] !== newpoints[ l - ps + 1 ] ) {
206
                                        for (m = 0; m < ps; ++m) {
207
                                                newpoints[ l + ps + m ] = newpoints[ l + m ];
208
                                        }
209
                                        newpoints[ l + 1 ] = newpoints[ l - ps + 1 ];
210
                                }
211
                        }
212
 
213
                        datapoints.points = newpoints;
214
                }
215
 
216
                plot.hooks.processDatapoints.push( computeFillBottoms );
217
        }
218
 
219
        $.plot.plugins.push({
220
                init: init,
221
                options: options,
222
                name: "fillbetween",
223
                version: "1.0"
224
        });
225
 
226
})(jQuery);