PluginProbe
Contact Forms by Cimatti / 1.9.2
Contact Forms by Cimatti v1.9.2
2.3.6 2.3.5 2.3.0 2.2.32 2.2.4 2.2.0 2.1.2 2.1.1 trunk 1.0 1.1 1.2 1.2.1 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 All 62 releases
contact-forms / flot / jquery.flot.stack.js

jquery.flot.stack.js in Contact Forms by Cimatti 1.9.2, at flot/jquery.flot.stack.js

185 lines 7.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /*
2 Flot plugin for stacking data sets, i.e. putting them on top of each
3 other, for accumulative graphs.
4
5 The plugin assumes the data is sorted on x (or y if stacking
6 horizontally). For line charts, it is assumed that if a line has an
7 undefined gap (from a null point), then the line above it should have
8 the same gap - insert zeros instead of "null" if you want another
9 behaviour. This also holds for the start and end of the chart. Note
10 that stacking a mix of positive and negative values in most instances
11 doesn't make sense (so it looks weird).
12
13 Two or more series are stacked when their "stack" attribute is set to
14 the same key (which can be any number or string or just "true"). To
15 specify the default stack, you can set
16
17 series: {
18 stack: null or true or key (number/string)
19 }
20
21 or specify it for a specific series
22
23 $.plot($("#placeholder"), [{ data: [ ... ], stack: true }])
24
25 The stacking order is determined by the order of the data series in
26 the array (later series end up on top of the previous).
27
28 Internally, the plugin modifies the datapoints in each series, adding
29 an offset to the y value. For line series, extra data points are
30 inserted through interpolation. If there's a second y value, it's also
31 adjusted (e.g for bar charts or filled areas).
32 */
33
34 (function ($) {
35 var options = {
36 series: { stack: null } // or number/string
37 };
38
39 function init(plot) {
40 function findMatchingSeries(s, allseries) {
41 var res = null
42 for (var i = 0; i < allseries.length; ++i) {
43 if (s == allseries[i])
44 break;
45
46 if (allseries[i].stack == s.stack)
47 res = allseries[i];
48 }
49
50 return res;
51 }
52
53 function stackData(plot, s, datapoints) {
54 if (s.stack == null)
55 return;
56
57 var other = findMatchingSeries(s, plot.getData());
58 if (!other)
59 return;
60
61 var ps = datapoints.pointsize,
62 points = datapoints.points,
63 otherps = other.datapoints.pointsize,
64 otherpoints = other.datapoints.points,
65 newpoints = [],
66 px, py, intery, qx, qy, bottom,
67 withlines = s.lines.show,
68 horizontal = s.bars.horizontal,
69 withbottom = ps > 2 && (horizontal ? datapoints.format[2].x : datapoints.format[2].y),
70 withsteps = withlines && s.lines.steps,
71 fromgap = true,
72 keyOffset = horizontal ? 1 : 0,
73 accumulateOffset = horizontal ? 0 : 1,
74 i = 0, j = 0, l;
75
76 while (true) {
77 if (i >= points.length)
78 break;
79
80 l = newpoints.length;
81
82 if (points[i] == null) {
83 // copy gaps
84 for (m = 0; m < ps; ++m)
85 newpoints.push(points[i + m]);
86 i += ps;
87 }
88 else if (j >= otherpoints.length) {
89 // for lines, we can't use the rest of the points
90 if (!withlines) {
91 for (m = 0; m < ps; ++m)
92 newpoints.push(points[i + m]);
93 }
94 i += ps;
95 }
96 else if (otherpoints[j] == null) {
97 // oops, got a gap
98 for (m = 0; m < ps; ++m)
99 newpoints.push(null);
100 fromgap = true;
101 j += otherps;
102 }
103 else {
104 // cases where we actually got two points
105 px = points[i + keyOffset];
106 py = points[i + accumulateOffset];
107 qx = otherpoints[j + keyOffset];
108 qy = otherpoints[j + accumulateOffset];
109 bottom = 0;
110
111 if (px == qx) {
112 for (m = 0; m < ps; ++m)
113 newpoints.push(points[i + m]);
114
115 newpoints[l + accumulateOffset] += qy;
116 bottom = qy;
117
118 i += ps;
119 j += otherps;
120 }
121 else if (px > qx) {
122 // we got past point below, might need to
123 // insert interpolated extra point
124 if (withlines && i > 0 && points[i - ps] != null) {
125 intery = py + (points[i - ps + accumulateOffset] - py) * (qx - px) / (points[i - ps + keyOffset] - px);
126 newpoints.push(qx);
127 newpoints.push(intery + qy);
128 for (m = 2; m < ps; ++m)
129 newpoints.push(points[i + m]);
130 bottom = qy;
131 }
132
133 j += otherps;
134 }
135 else { // px < qx
136 if (fromgap && withlines) {
137 // if we come from a gap, we just skip this point
138 i += ps;
139 continue;
140 }
141
142 for (m = 0; m < ps; ++m)
143 newpoints.push(points[i + m]);
144
145 // we might be able to interpolate a point below,
146 // this can give us a better y
147 if (withlines && j > 0 && otherpoints[j - otherps] != null)
148 bottom = qy + (otherpoints[j - otherps + accumulateOffset] - qy) * (px - qx) / (otherpoints[j - otherps + keyOffset] - qx);
149
150 newpoints[l + accumulateOffset] += bottom;
151
152 i += ps;
153 }
154
155 fromgap = false;
156
157 if (l != newpoints.length && withbottom)
158 newpoints[l + 2] += bottom;
159 }
160
161 // maintain the line steps invariant
162 if (withsteps && l != newpoints.length && l > 0
163 && newpoints[l] != null
164 && newpoints[l] != newpoints[l - ps]
165 && newpoints[l + 1] != newpoints[l - ps + 1]) {
166 for (m = 0; m < ps; ++m)
167 newpoints[l + ps + m] = newpoints[l + m];
168 newpoints[l + 1] = newpoints[l - ps + 1];
169 }
170 }
171
172 datapoints.points = newpoints;
173 }
174
175 plot.hooks.processDatapoints.push(stackData);
176 }
177
178 $.plot.plugins.push({
179 init: init,
180 options: options,
181 name: 'stack',
182 version: '1.2'
183 });
184 })(jQuery);
185