You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			227 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			JavaScript
		
	
			
		
		
	
	
			227 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			JavaScript
		
	
| /* 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);
 |