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