Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

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