OLD | NEW |
(Empty) | |
| 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 b
ottom |
| 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 |
| 34 var options = { |
| 35 series: { |
| 36 fillBetween: null // or number |
| 37 } |
| 38 }; |
| 39 |
| 40 function init( plot ) { |
| 41 |
| 42 function findBottomSeries( s, allseries ) { |
| 43 |
| 44 var i; |
| 45 |
| 46 for ( i = 0; i < allseries.length; ++i ) { |
| 47 if ( allseries[ i ].id === s.fillBetween ) { |
| 48 return allseries[ i ]; |
| 49 } |
| 50 } |
| 51 |
| 52 if ( typeof s.fillBetween === "number" ) { |
| 53 if ( s.fillBetween < 0 || s.fillBetween >= allse
ries.length ) { |
| 54 return null; |
| 55 } |
| 56 return allseries[ s.fillBetween ]; |
| 57 } |
| 58 |
| 59 return null; |
| 60 } |
| 61 |
| 62 function computeFillBottoms( plot, s, datapoints ) { |
| 63 |
| 64 if ( s.fillBetween == null ) { |
| 65 return; |
| 66 } |
| 67 |
| 68 var other = findBottomSeries( s, plot.getData() ); |
| 69 |
| 70 if ( !other ) { |
| 71 return; |
| 72 } |
| 73 |
| 74 var ps = datapoints.pointsize, |
| 75 points = datapoints.points, |
| 76 otherps = other.datapoints.pointsize, |
| 77 otherpoints = other.datapoints.points, |
| 78 newpoints = [], |
| 79 px, py, intery, qx, qy, bottom, |
| 80 withlines = s.lines.show, |
| 81 withbottom = ps > 2 && datapoints.format[2].y, |
| 82 withsteps = withlines && s.lines.steps, |
| 83 fromgap = true, |
| 84 i = 0, |
| 85 j = 0, |
| 86 l, m; |
| 87 |
| 88 while ( true ) { |
| 89 |
| 90 if ( i >= points.length ) { |
| 91 break; |
| 92 } |
| 93 |
| 94 l = newpoints.length; |
| 95 |
| 96 if ( points[ i ] == null ) { |
| 97 |
| 98 // copy gaps |
| 99 |
| 100 for ( m = 0; m < ps; ++m ) { |
| 101 newpoints.push( points[ i + m ]
); |
| 102 } |
| 103 |
| 104 i += ps; |
| 105 |
| 106 } else if ( j >= otherpoints.length ) { |
| 107 |
| 108 // for lines, we can't use the rest of t
he points |
| 109 |
| 110 if ( !withlines ) { |
| 111 for ( m = 0; m < ps; ++m ) { |
| 112 newpoints.push( points[
i + m ] ); |
| 113 } |
| 114 } |
| 115 |
| 116 i += ps; |
| 117 |
| 118 } else if ( otherpoints[ j ] == null ) { |
| 119 |
| 120 // oops, got a gap |
| 121 |
| 122 for ( m = 0; m < ps; ++m ) { |
| 123 newpoints.push( null ); |
| 124 } |
| 125 |
| 126 fromgap = true; |
| 127 j += otherps; |
| 128 |
| 129 } else { |
| 130 |
| 131 // cases where we actually got two point
s |
| 132 |
| 133 px = points[ i ]; |
| 134 py = points[ i + 1 ]; |
| 135 qx = otherpoints[ j ]; |
| 136 qy = otherpoints[ j + 1 ]; |
| 137 bottom = 0; |
| 138 |
| 139 if ( px === qx ) { |
| 140 |
| 141 for ( m = 0; m < ps; ++m ) { |
| 142 newpoints.push( points[
i + m ] ); |
| 143 } |
| 144 |
| 145 //newpoints[ l + 1 ] += qy; |
| 146 bottom = qy; |
| 147 |
| 148 i += ps; |
| 149 j += otherps; |
| 150 |
| 151 } else if ( px > qx ) { |
| 152 |
| 153 // we got past point below, migh
t need to |
| 154 // insert interpolated extra poi
nt |
| 155 |
| 156 if ( withlines && i > 0 && point
s[ i - ps ] != null ) { |
| 157 intery = py + ( points[
i - ps + 1 ] - py ) * ( qx - px ) / ( points[ i - ps ] - px ); |
| 158 newpoints.push( qx ); |
| 159 newpoints.push( intery )
; |
| 160 for ( m = 2; m < ps; ++m
) { |
| 161 newpoints.push(
points[ i + m ] ); |
| 162 } |
| 163 bottom = qy; |
| 164 } |
| 165 |
| 166 j += otherps; |
| 167 |
| 168 } else { // px < qx |
| 169 |
| 170 // if we come from a gap, we jus
t skip this point |
| 171 |
| 172 if ( fromgap && withlines ) { |
| 173 i += ps; |
| 174 continue; |
| 175 } |
| 176 |
| 177 for ( m = 0; m < ps; ++m ) { |
| 178 newpoints.push( points[
i + m ] ); |
| 179 } |
| 180 |
| 181 // we might be able to interpola
te a point below, |
| 182 // this can give us a better y |
| 183 |
| 184 if ( withlines && j > 0 && other
points[ j - otherps ] != null ) { |
| 185 bottom = qy + ( otherpoi
nts[ j - otherps + 1 ] - qy ) * ( px - qx ) / ( otherpoints[ j - otherps ] - qx
); |
| 186 } |
| 187 |
| 188 //newpoints[l + 1] += bottom; |
| 189 |
| 190 i += ps; |
| 191 } |
| 192 |
| 193 fromgap = false; |
| 194 |
| 195 if ( l !== newpoints.length && withbotto
m ) { |
| 196 newpoints[ l + 2 ] = bottom; |
| 197 } |
| 198 } |
| 199 |
| 200 // maintain the line steps invariant |
| 201 |
| 202 if ( withsteps && l !== newpoints.length && l >
0 && |
| 203 newpoints[ l ] !== null && |
| 204 newpoints[ l ] !== newpoints[ l - ps ] &
& |
| 205 newpoints[ l + 1 ] !== newpoints[ l - ps
+ 1 ] ) { |
| 206 for (m = 0; m < ps; ++m) { |
| 207 newpoints[ l + ps + m ] = newpoi
nts[ l + m ]; |
| 208 } |
| 209 newpoints[ l + 1 ] = newpoints[ l - ps +
1 ]; |
| 210 } |
| 211 } |
| 212 |
| 213 datapoints.points = newpoints; |
| 214 } |
| 215 |
| 216 plot.hooks.processDatapoints.push( computeFillBottoms ); |
| 217 } |
| 218 |
| 219 $.plot.plugins.push({ |
| 220 init: init, |
| 221 options: options, |
| 222 name: "fillbetween", |
| 223 version: "1.0" |
| 224 }); |
| 225 |
| 226 })(jQuery); |
OLD | NEW |