Index: third_party/flot/jquery.flot.fillbetween.js |
diff --git a/third_party/flot/jquery.flot.fillbetween.js b/third_party/flot/jquery.flot.fillbetween.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..18b15d26db8c91e8527ea35f87d39674bb8f1c70 |
--- /dev/null |
+++ b/third_party/flot/jquery.flot.fillbetween.js |
@@ -0,0 +1,226 @@ |
+/* Flot plugin for computing bottoms for filled line and bar charts. |
+ |
+Copyright (c) 2007-2014 IOLA and Ole Laursen. |
+Licensed under the MIT license. |
+ |
+The case: you've got two series that you want to fill the area between. In Flot |
+terms, you need to use one as the fill bottom of the other. You can specify the |
+bottom of each data point as the third coordinate manually, or you can use this |
+plugin to compute it for you. |
+ |
+In order to name the other series, you need to give it an id, like this: |
+ |
+ var dataset = [ |
+ { data: [ ... ], id: "foo" } , // use default bottom |
+ { data: [ ... ], fillBetween: "foo" }, // use first dataset as bottom |
+ ]; |
+ |
+ $.plot($("#placeholder"), dataset, { lines: { show: true, fill: true }}); |
+ |
+As a convenience, if the id given is a number that doesn't appear as an id in |
+the series, it is interpreted as the index in the array instead (so fillBetween: |
+0 can also mean the first series). |
+ |
+Internally, the plugin modifies the datapoints in each series. For line series, |
+extra data points might be inserted through interpolation. Note that at points |
+where the bottom line is not defined (due to a null point or start/end of line), |
+the current line will show a gap too. The algorithm comes from the |
+jquery.flot.stack.js plugin, possibly some code could be shared. |
+ |
+*/ |
+ |
+(function ( $ ) { |
+ |
+ var options = { |
+ series: { |
+ fillBetween: null // or number |
+ } |
+ }; |
+ |
+ function init( plot ) { |
+ |
+ function findBottomSeries( s, allseries ) { |
+ |
+ var i; |
+ |
+ for ( i = 0; i < allseries.length; ++i ) { |
+ if ( allseries[ i ].id === s.fillBetween ) { |
+ return allseries[ i ]; |
+ } |
+ } |
+ |
+ if ( typeof s.fillBetween === "number" ) { |
+ if ( s.fillBetween < 0 || s.fillBetween >= allseries.length ) { |
+ return null; |
+ } |
+ return allseries[ s.fillBetween ]; |
+ } |
+ |
+ return null; |
+ } |
+ |
+ function computeFillBottoms( plot, s, datapoints ) { |
+ |
+ if ( s.fillBetween == null ) { |
+ return; |
+ } |
+ |
+ var other = findBottomSeries( 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, |
+ withbottom = ps > 2 && datapoints.format[2].y, |
+ withsteps = withlines && s.lines.steps, |
+ fromgap = true, |
+ i = 0, |
+ j = 0, |
+ l, m; |
+ |
+ while ( true ) { |
+ |
+ if ( i >= points.length ) { |
+ break; |
+ } |
+ |
+ l = newpoints.length; |
+ |
+ if ( points[ i ] == null ) { |
+ |
+ // copy gaps |
+ |
+ for ( m = 0; m < ps; ++m ) { |
+ newpoints.push( points[ i + m ] ); |
+ } |
+ |
+ i += ps; |
+ |
+ } else if ( j >= otherpoints.length ) { |
+ |
+ // for lines, we can't use the rest of the points |
+ |
+ if ( !withlines ) { |
+ for ( m = 0; m < ps; ++m ) { |
+ newpoints.push( points[ i + m ] ); |
+ } |
+ } |
+ |
+ i += ps; |
+ |
+ } else if ( otherpoints[ j ] == null ) { |
+ |
+ // oops, got a gap |
+ |
+ for ( m = 0; m < ps; ++m ) { |
+ newpoints.push( null ); |
+ } |
+ |
+ fromgap = true; |
+ j += otherps; |
+ |
+ } 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 ); |
+ for ( m = 2; m < ps; ++m ) { |
+ newpoints.push( points[ i + m ] ); |
+ } |
+ bottom = qy; |
+ } |
+ |
+ j += otherps; |
+ |
+ } else { // px < qx |
+ |
+ // if we come from a gap, we just skip this point |
+ |
+ if ( fromgap && withlines ) { |
+ i += ps; |
+ continue; |
+ } |
+ |
+ 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 - otherps ] != null ) { |
+ bottom = qy + ( otherpoints[ j - otherps + 1 ] - qy ) * ( px - qx ) / ( otherpoints[ j - otherps ] - qx ); |
+ } |
+ |
+ //newpoints[l + 1] += bottom; |
+ |
+ i += ps; |
+ } |
+ |
+ fromgap = false; |
+ |
+ if ( l !== newpoints.length && withbottom ) { |
+ 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( computeFillBottoms ); |
+ } |
+ |
+ $.plot.plugins.push({ |
+ init: init, |
+ options: options, |
+ name: "fillbetween", |
+ version: "1.0" |
+ }); |
+ |
+})(jQuery); |