src/pyams_skin/resources/js/ext/flot/jquery.flot.fillbetween.js
changeset 566 a1707c607eec
parent 565 318533413200
child 567 bca1726b1d85
equal deleted inserted replaced
565:318533413200 566:a1707c607eec
     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 0 can also mean the first series).
       
    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     var options = {
       
    34         series: {
       
    35             fillBetween: null    // or number
       
    36         }
       
    37     };
       
    38 
       
    39     function init(plot) {
       
    40         function findBottomSeries(s, allseries) {
       
    41             var i;
       
    42 
       
    43             for (i = 0; i < allseries.length; ++i) {
       
    44                 if (allseries[ i ].id === s.fillBetween) {
       
    45                     return allseries[ i ];
       
    46                 }
       
    47             }
       
    48 
       
    49             if (typeof s.fillBetween === "number") {
       
    50                 if (s.fillBetween < 0 || s.fillBetween >= allseries.length) {
       
    51                     return null;
       
    52                 }
       
    53                 return allseries[ s.fillBetween ];
       
    54             }
       
    55 
       
    56             return null;
       
    57         }
       
    58 
       
    59         function computeFormat(plot, s, data, datapoints) {
       
    60             if (s.fillBetween == null) {
       
    61                 return;
       
    62             }
       
    63             
       
    64             format = datapoints.format;
       
    65             var plotHasId = function(id) {
       
    66                 var plotData = plot.getData();
       
    67                 for (i = 0; i < plotData.length; i++) {
       
    68                     if (plotData[i].id === id) {
       
    69                         return true;
       
    70                     }
       
    71                 }
       
    72 
       
    73                 return false;
       
    74             }
       
    75 
       
    76             if (!format) {
       
    77                 format = [];
       
    78 
       
    79                 format.push({ 
       
    80                     x: true, 
       
    81                     number: true, 
       
    82                     computeRange: s.xaxis.options.autoScale !== 'none',
       
    83                     required: true 
       
    84                 });
       
    85                 format.push({ 
       
    86                     y: true, 
       
    87                     number: true, 
       
    88                     computeRange: s.yaxis.options.autoScale !== 'none',
       
    89                     required: true 
       
    90                 });
       
    91 
       
    92                 if (s.fillBetween !== undefined && s.fillBetween !== '' && plotHasId(s.fillBetween) && s.fillBetween !== s.id) {
       
    93                     format.push({
       
    94                         x: false,
       
    95                         y: true,
       
    96                         number: true,
       
    97                         required: false,
       
    98                         computeRange: s.yaxis.options.autoScale !== 'none',
       
    99                         defaultValue: 0
       
   100                     });
       
   101                 }
       
   102 
       
   103                 datapoints.format = format;
       
   104             }
       
   105         }
       
   106 
       
   107         function computeFillBottoms(plot, s, datapoints) {
       
   108             if (s.fillBetween == null) {
       
   109                 return;
       
   110             }
       
   111 
       
   112             var other = findBottomSeries(s, plot.getData());
       
   113 
       
   114             if (!other) {
       
   115                 return;
       
   116             }
       
   117 
       
   118             var ps = datapoints.pointsize,
       
   119                 points = datapoints.points,
       
   120                 otherps = other.datapoints.pointsize,
       
   121                 otherpoints = other.datapoints.points,
       
   122                 newpoints = [],
       
   123                 px, py, intery, qx, qy, bottom,
       
   124                 withlines = s.lines.show,
       
   125                 withbottom = ps > 2 && datapoints.format[2].y,
       
   126                 withsteps = withlines && s.lines.steps,
       
   127                 fromgap = true,
       
   128                 i = 0,
       
   129                 j = 0,
       
   130                 l, m;
       
   131 
       
   132             while (true) {
       
   133                 if (i >= points.length) {
       
   134                     break;
       
   135                 }
       
   136 
       
   137                 l = newpoints.length;
       
   138 
       
   139                 if (points[ i ] == null) {
       
   140                     // copy gaps
       
   141                     for (m = 0; m < ps; ++m) {
       
   142                         newpoints.push(points[ i + m ]);
       
   143                     }
       
   144 
       
   145                     i += ps;
       
   146                 } else if (j >= otherpoints.length) {
       
   147                     // for lines, we can't use the rest of the points
       
   148                     if (!withlines) {
       
   149                         for (m = 0; m < ps; ++m) {
       
   150                             newpoints.push(points[ i + m ]);
       
   151                         }
       
   152                     }
       
   153 
       
   154                     i += ps;
       
   155                 } else if (otherpoints[ j ] == null) {
       
   156                     // oops, got a gap
       
   157                     for (m = 0; m < ps; ++m) {
       
   158                         newpoints.push(null);
       
   159                     }
       
   160 
       
   161                     fromgap = true;
       
   162                     j += otherps;
       
   163                 } else {
       
   164                     // cases where we actually got two points
       
   165                     px = points[ i ];
       
   166                     py = points[ i + 1 ];
       
   167                     qx = otherpoints[ j ];
       
   168                     qy = otherpoints[ j + 1 ];
       
   169                     bottom = 0;
       
   170 
       
   171                     if (px === qx) {
       
   172                         for (m = 0; m < ps; ++m) {
       
   173                             newpoints.push(points[ i + m ]);
       
   174                         }
       
   175 
       
   176                         //newpoints[ l + 1 ] += qy;
       
   177                         bottom = qy;
       
   178 
       
   179                         i += ps;
       
   180                         j += otherps;
       
   181                     } else if (px > qx) {
       
   182                         // we got past point below, might need to
       
   183                         // insert interpolated extra point
       
   184 
       
   185                         if (withlines && i > 0 && points[ i - ps ] != null) {
       
   186                             intery = py + (points[ i - ps + 1 ] - py) * (qx - px) / (points[ i - ps ] - px);
       
   187                             newpoints.push(qx);
       
   188                             newpoints.push(intery);
       
   189                             for (m = 2; m < ps; ++m) {
       
   190                                 newpoints.push(points[ i + m ]);
       
   191                             }
       
   192                             bottom = qy;
       
   193                         }
       
   194 
       
   195                         j += otherps;
       
   196                     } else {
       
   197                         // px < qx
       
   198                         // if we come from a gap, we just skip this point
       
   199 
       
   200                         if (fromgap && withlines) {
       
   201                             i += ps;
       
   202                             continue;
       
   203                         }
       
   204 
       
   205                         for (m = 0; m < ps; ++m) {
       
   206                             newpoints.push(points[ i + m ]);
       
   207                         }
       
   208 
       
   209                         // we might be able to interpolate a point below,
       
   210                         // this can give us a better y
       
   211 
       
   212                         if (withlines && j > 0 && otherpoints[ j - otherps ] != null) {
       
   213                             bottom = qy + (otherpoints[ j - otherps + 1 ] - qy) * (px - qx) / (otherpoints[ j - otherps ] - qx);
       
   214                         }
       
   215 
       
   216                         //newpoints[l + 1] += bottom;
       
   217 
       
   218                         i += ps;
       
   219                     }
       
   220 
       
   221                     fromgap = false;
       
   222 
       
   223                     if (l !== newpoints.length && withbottom) {
       
   224                         newpoints[ l + 2 ] = bottom;
       
   225                     }
       
   226                 }
       
   227 
       
   228                 // maintain the line steps invariant
       
   229 
       
   230                 if (withsteps && l !== newpoints.length && l > 0 &&
       
   231                     newpoints[ l ] !== null &&
       
   232                     newpoints[ l ] !== newpoints[ l - ps ] &&
       
   233                     newpoints[ l + 1 ] !== newpoints[ l - ps + 1 ]) {
       
   234                     for (m = 0; m < ps; ++m) {
       
   235                         newpoints[ l + ps + m ] = newpoints[ l + m ];
       
   236                     }
       
   237                     newpoints[ l + 1 ] = newpoints[ l - ps + 1 ];
       
   238                 }
       
   239             }
       
   240 
       
   241             datapoints.points = newpoints;
       
   242         }
       
   243 
       
   244         plot.hooks.processRawData.push(computeFormat);
       
   245         plot.hooks.processDatapoints.push(computeFillBottoms);
       
   246     }
       
   247 
       
   248     $.plot.plugins.push({
       
   249         init: init,
       
   250         options: options,
       
   251         name: "fillbetween",
       
   252         version: "1.0"
       
   253     });
       
   254 })(jQuery);