123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- /*
- Flot plugin for stacking data sets, i.e. putting them on top of each
- other, for accumulative graphs. Note that the plugin assumes the data
- is sorted on x. Also note that stacking a mix of positive and negative
- values in most instances doesn't make sense (so it looks weird).
-
- Two or more series are stacked when their "stack" attribute is set to
- the same key (which can be any number or string or just "true"). To
- specify the default stack, you can set
-
- series: {
- stack: null or true or key (number/string)
- }
-
- or specify it for a specific series
-
- $.plot($("#placeholder"), [{ data: [ ... ], stack: true ])
-
- The stacking order is determined by the order of the data series in
- the array (later series end up on top of the previous).
-
- Internally, the plugin modifies the datapoints in each series, adding
- an offset to the y value. For line series, extra data points are
- inserted through interpolation. For bar charts, the second y value is
- also adjusted.
- */
-
- (function ($) {
- var options = {
- series: { stack: null } // or number/string
- };
-
- function init(plot) {
- function findMatchingSeries(s, allseries) {
- var res = null
- for (var i = 0; i < allseries.length; ++i) {
- if (s == allseries[i])
- break;
-
- if (allseries[i].stack == s.stack)
- res = allseries[i];
- }
-
- return res;
- }
-
- function stackData(plot, s, datapoints) {
- if (s.stack == null)
- return;
-
- var other = findMatchingSeries(s, plot.getData());
- if (!other)
- return;
-
- var ps = datapoints.pointsize,
- points = datapoints.points,
- otherps = other.datapoints.pointsize,
- otherpoints = other.datapoints.points,
- newpoints = [],
- px, py, intery, qx, qy, bottom,
- withlines = s.lines.show, withbars = s.bars.show,
- withsteps = withlines && s.lines.steps,
- i = 0, j = 0, l;
-
- while (true) {
- if (i >= points.length)
- break;
-
- l = newpoints.length;
-
- if (j >= otherpoints.length
- || otherpoints[j] == null
- || points[i] == null) {
- // degenerate cases
- for (m = 0; m < ps; ++m)
- newpoints.push(points[i + m]);
- i += ps;
- }
- else {
- // cases where we actually got two points
- px = points[i];
- py = points[i + 1];
- qx = otherpoints[j];
- qy = otherpoints[j + 1];
- bottom = 0;
-
- if (px == qx) {
- for (m = 0; m < ps; ++m)
- newpoints.push(points[i + m]);
-
- newpoints[l + 1] += qy;
- bottom = qy;
-
- i += ps;
- j += otherps;
- }
- else if (px > qx) {
- // we got past point below, might need to
- // insert interpolated extra point
- if (withlines && i > 0 && points[i - ps] != null) {
- intery = py + (points[i - ps + 1] - py) * (qx - px) / (points[i - ps] - px);
- newpoints.push(qx);
- newpoints.push(intery + qy)
- for (m = 2; m < ps; ++m)
- newpoints.push(points[i + m]);
- bottom = qy;
- }
-
- j += otherps;
- }
- else {
- for (m = 0; m < ps; ++m)
- newpoints.push(points[i + m]);
-
- // we might be able to interpolate a point below,
- // this can give us a better y
- if (withlines && j > 0 && otherpoints[j - ps] != null)
- bottom = qy + (otherpoints[j - ps + 1] - qy) * (px - qx) / (otherpoints[j - ps] - qx);
-
- newpoints[l + 1] += bottom;
-
- i += ps;
- }
-
- if (l != newpoints.length && withbars)
- newpoints[l + 2] += bottom;
- }
-
- // maintain the line steps invariant
- if (withsteps && l != newpoints.length && l > 0
- && newpoints[l] != null
- && newpoints[l] != newpoints[l - ps]
- && newpoints[l + 1] != newpoints[l - ps + 1]) {
- for (m = 0; m < ps; ++m)
- newpoints[l + ps + m] = newpoints[l + m];
- newpoints[l + 1] = newpoints[l - ps + 1];
- }
- }
-
- datapoints.points = newpoints;
- }
-
- plot.hooks.processDatapoints.push(stackData);
- }
-
- $.plot.plugins.push({
- init: init,
- options: options,
- name: 'stack',
- version: '1.0'
- });
- })(jQuery);
|