http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/7e1546d8/blur-console/src/main/webapp/libs/flot/jquery.flot.canvas.js
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/libs/flot/jquery.flot.canvas.js 
b/blur-console/src/main/webapp/libs/flot/jquery.flot.canvas.js
new file mode 100644
index 0000000..d94b961
--- /dev/null
+++ b/blur-console/src/main/webapp/libs/flot/jquery.flot.canvas.js
@@ -0,0 +1,345 @@
+/* Flot plugin for drawing all elements of a plot on the canvas.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+Flot normally produces certain elements, like axis labels and the legend, using
+HTML elements. This permits greater interactivity and customization, and often
+looks better, due to cross-browser canvas text inconsistencies and limitations.
+
+It can also be desirable to render the plot entirely in canvas, particularly
+if the goal is to save it as an image, or if Flot is being used in a context
+where the HTML DOM does not exist, as is the case within Node.js. This plugin
+switches out Flot's standard drawing operations for canvas-only replacements.
+
+Currently the plugin supports only axis labels, but it will eventually allow
+every element of the plot to be rendered directly to canvas.
+
+The plugin supports these options:
+
+{
+    canvas: boolean
+}
+
+The "canvas" option controls whether full canvas drawing is enabled, making it
+possible to toggle on and off. This is useful when a plot uses HTML text in the
+browser, but needs to redraw with canvas text when exporting as an image.
+
+*/
+
+(function($) {
+
+       var options = {
+               canvas: true
+       };
+
+       var render, getTextInfo, addText;
+
+       // Cache the prototype hasOwnProperty for faster access
+
+       var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+       function init(plot, classes) {
+
+               var Canvas = classes.Canvas;
+
+               // We only want to replace the functions once; the second time 
around
+               // we would just get our new function back.  This whole 
replacing of
+               // prototype functions is a disaster, and needs to be changed 
ASAP.
+
+               if (render == null) {
+                       getTextInfo = Canvas.prototype.getTextInfo,
+                       addText = Canvas.prototype.addText,
+                       render = Canvas.prototype.render;
+               }
+
+               // Finishes rendering the canvas, including overlaid text
+
+               Canvas.prototype.render = function() {
+
+                       if (!plot.getOptions().canvas) {
+                               return render.call(this);
+                       }
+
+                       var context = this.context,
+                               cache = this._textCache;
+
+                       // For each text layer, render elements marked as active
+
+                       context.save();
+                       context.textBaseline = "middle";
+
+                       for (var layerKey in cache) {
+                               if (hasOwnProperty.call(cache, layerKey)) {
+                                       var layerCache = cache[layerKey];
+                                       for (var styleKey in layerCache) {
+                                               if 
(hasOwnProperty.call(layerCache, styleKey)) {
+                                                       var styleCache = 
layerCache[styleKey],
+                                                               updateStyles = 
true;
+                                                       for (var key in 
styleCache) {
+                                                               if 
(hasOwnProperty.call(styleCache, key)) {
+
+                                                                       var 
info = styleCache[key],
+                                                                               
positions = info.positions,
+                                                                               
lines = info.lines;
+
+                                                                       // 
Since every element at this level of the cache have the
+                                                                       // same 
font and fill styles, we can just change them once
+                                                                       // 
using the values from the first element.
+
+                                                                       if 
(updateStyles) {
+                                                                               
context.fillStyle = info.font.color;
+                                                                               
context.font = info.font.definition;
+                                                                               
updateStyles = false;
+                                                                       }
+
+                                                                       for 
(var i = 0, position; position = positions[i]; i++) {
+                                                                               
if (position.active) {
+                                                                               
        for (var j = 0, line; line = position.lines[j]; j++) {
+                                                                               
                context.fillText(lines[j].text, line[0], line[1]);
+                                                                               
        }
+                                                                               
} else {
+                                                                               
        positions.splice(i--, 1);
+                                                                               
}
+                                                                       }
+
+                                                                       if 
(positions.length == 0) {
+                                                                               
delete styleCache[key];
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       context.restore();
+               };
+
+               // Creates (if necessary) and returns a text info object.
+               //
+               // When the canvas option is set, the object looks like this:
+               //
+               // {
+               //     width: Width of the text's bounding box.
+               //     height: Height of the text's bounding box.
+               //     positions: Array of positions at which this text is 
drawn.
+               //     lines: [{
+               //         height: Height of this line.
+               //         widths: Width of this line.
+               //         text: Text on this line.
+               //     }],
+               //     font: {
+               //         definition: Canvas font property string.
+               //         color: Color of the text.
+               //     },
+               // }
+               //
+               // The positions array contains objects that look like this:
+               //
+               // {
+               //     active: Flag indicating whether the text should be 
visible.
+               //     lines: Array of [x, y] coordinates at which to draw the 
line.
+               //     x: X coordinate at which to draw the text.
+               //     y: Y coordinate at which to draw the text.
+               // }
+
+               Canvas.prototype.getTextInfo = function(layer, text, font, 
angle, width) {
+
+                       if (!plot.getOptions().canvas) {
+                               return getTextInfo.call(this, layer, text, 
font, angle, width);
+                       }
+
+                       var textStyle, layerCache, styleCache, info;
+
+                       // Cast the value to a string, in case we were given a 
number
+
+                       text = "" + text;
+
+                       // If the font is a font-spec object, generate a CSS 
definition
+
+                       if (typeof font === "object") {
+                               textStyle = font.style + " " + font.variant + " 
" + font.weight + " " + font.size + "px " + font.family;
+                       } else {
+                               textStyle = font;
+                       }
+
+                       // Retrieve (or create) the cache for the text's layer 
and styles
+
+                       layerCache = this._textCache[layer];
+
+                       if (layerCache == null) {
+                               layerCache = this._textCache[layer] = {};
+                       }
+
+                       styleCache = layerCache[textStyle];
+
+                       if (styleCache == null) {
+                               styleCache = layerCache[textStyle] = {};
+                       }
+
+                       info = styleCache[text];
+
+                       if (info == null) {
+
+                               var context = this.context;
+
+                               // If the font was provided as CSS, create a 
div with those
+                               // classes and examine it to generate a canvas 
font spec.
+
+                               if (typeof font !== "object") {
+
+                                       var element = $("<div>&nbsp;</div>")
+                                               .css("position", "absolute")
+                                               .addClass(typeof font === 
"string" ? font : null)
+                                               
.appendTo(this.getTextLayer(layer));
+
+                                       font = {
+                                               lineHeight: element.height(),
+                                               style: 
element.css("font-style"),
+                                               variant: 
element.css("font-variant"),
+                                               weight: 
element.css("font-weight"),
+                                               family: 
element.css("font-family"),
+                                               color: element.css("color")
+                                       };
+
+                                       // Setting line-height to 1, without 
units, sets it equal
+                                       // to the font-size, even if the 
font-size is abstract,
+                                       // like 'smaller'.  This enables us to 
read the real size
+                                       // via the element's height, working 
around browsers that
+                                       // return the literal 'smaller' value.
+
+                                       font.size = element.css("line-height", 
1).height();
+
+                                       element.remove();
+                               }
+
+                               textStyle = font.style + " " + font.variant + " 
" + font.weight + " " + font.size + "px " + font.family;
+
+                               // Create a new info object, initializing the 
dimensions to
+                               // zero so we can count them up line-by-line.
+
+                               info = styleCache[text] = {
+                                       width: 0,
+                                       height: 0,
+                                       positions: [],
+                                       lines: [],
+                                       font: {
+                                               definition: textStyle,
+                                               color: font.color
+                                       }
+                               };
+
+                               context.save();
+                               context.font = textStyle;
+
+                               // Canvas can't handle multi-line strings; 
break on various
+                               // newlines, including HTML brs, to build a 
list of lines.
+                               // Note that we could split directly on 
regexps, but IE < 9 is
+                               // broken; revisit when we drop IE 7/8 support.
+
+                               var lines = (text + "").replace(/<br 
?\/?>|\r\n|\r/g, "\n").split("\n");
+
+                               for (var i = 0; i < lines.length; ++i) {
+
+                                       var lineText = lines[i],
+                                               measured = 
context.measureText(lineText);
+
+                                       info.width = Math.max(measured.width, 
info.width);
+                                       info.height += font.lineHeight;
+
+                                       info.lines.push({
+                                               text: lineText,
+                                               width: measured.width,
+                                               height: font.lineHeight
+                                       });
+                               }
+
+                               context.restore();
+                       }
+
+                       return info;
+               };
+
+               // Adds a text string to the canvas text overlay.
+
+               Canvas.prototype.addText = function(layer, x, y, text, font, 
angle, width, halign, valign) {
+
+                       if (!plot.getOptions().canvas) {
+                               return addText.call(this, layer, x, y, text, 
font, angle, width, halign, valign);
+                       }
+
+                       var info = this.getTextInfo(layer, text, font, angle, 
width),
+                               positions = info.positions,
+                               lines = info.lines;
+
+                       // Text is drawn with baseline 'middle', which we need 
to account
+                       // for by adding half a line's height to the y position.
+
+                       y += info.height / lines.length / 2;
+
+                       // Tweak the initial y-position to match vertical 
alignment
+
+                       if (valign == "middle") {
+                               y = Math.round(y - info.height / 2);
+                       } else if (valign == "bottom") {
+                               y = Math.round(y - info.height);
+                       } else {
+                               y = Math.round(y);
+                       }
+
+                       // FIXME: LEGACY BROWSER FIX
+                       // AFFECTS: Opera < 12.00
+
+                       // Offset the y coordinate, since Opera is off pretty
+                       // consistently compared to the other browsers.
+
+                       if (!!(window.opera && 
window.opera.version().split(".")[0] < 12)) {
+                               y -= 2;
+                       }
+
+                       // Determine whether this text already exists at this 
position.
+                       // If so, mark it for inclusion in the next render pass.
+
+                       for (var i = 0, position; position = positions[i]; i++) 
{
+                               if (position.x == x && position.y == y) {
+                                       position.active = true;
+                                       return;
+                               }
+                       }
+
+                       // If the text doesn't exist at this position, create a 
new entry
+
+                       position = {
+                               active: true,
+                               lines: [],
+                               x: x,
+                               y: y
+                       };
+
+                       positions.push(position);
+
+                       // Fill in the x & y positions of each line, adjusting 
them
+                       // individually for horizontal alignment.
+
+                       for (var i = 0, line; line = lines[i]; i++) {
+                               if (halign == "center") {
+                                       position.lines.push([Math.round(x - 
line.width / 2), y]);
+                               } else if (halign == "right") {
+                                       position.lines.push([Math.round(x - 
line.width), y]);
+                               } else {
+                                       position.lines.push([Math.round(x), y]);
+                               }
+                               y += line.height;
+                       }
+               };
+       }
+
+       $.plot.plugins.push({
+               init: init,
+               options: options,
+               name: "canvas",
+               version: "1.0"
+       });
+
+})(jQuery);

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/7e1546d8/blur-console/src/main/webapp/libs/flot/jquery.flot.categories.js
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/libs/flot/jquery.flot.categories.js 
b/blur-console/src/main/webapp/libs/flot/jquery.flot.categories.js
new file mode 100644
index 0000000..6e6e8ba
--- /dev/null
+++ b/blur-console/src/main/webapp/libs/flot/jquery.flot.categories.js
@@ -0,0 +1,190 @@
+/* Flot plugin for plotting textual data or categories.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+Consider a dataset like [["February", 34], ["March", 20], ...]. This plugin
+allows you to plot such a dataset directly.
+
+To enable it, you must specify mode: "categories" on the axis with the textual
+labels, e.g.
+
+       $.plot("#placeholder", data, { xaxis: { mode: "categories" } });
+
+By default, the labels are ordered as they are met in the data series. If you
+need a different ordering, you can specify "categories" on the axis options
+and list the categories there:
+
+       xaxis: {
+               mode: "categories",
+               categories: ["February", "March", "April"]
+       }
+
+If you need to customize the distances between the categories, you can specify
+"categories" as an object mapping labels to values
+
+       xaxis: {
+               mode: "categories",
+               categories: { "February": 1, "March": 3, "April": 4 }
+       }
+
+If you don't specify all categories, the remaining categories will be numbered
+from the max value plus 1 (with a spacing of 1 between each).
+
+Internally, the plugin works by transforming the input data through an auto-
+generated mapping where the first category becomes 0, the second 1, etc.
+Hence, a point like ["February", 34] becomes [0, 34] internally in Flot (this
+is visible in hover and click events that return numbers rather than the
+category labels). The plugin also overrides the tick generator to spit out the
+categories as ticks instead of the values.
+
+If you need to map a value back to its label, the mapping is always accessible
+as "categories" on the axis object, e.g. plot.getAxes().xaxis.categories.
+
+*/
+
+(function ($) {
+    var options = {
+        xaxis: {
+            categories: null
+        },
+        yaxis: {
+            categories: null
+        }
+    };
+    
+    function processRawData(plot, series, data, datapoints) {
+        // if categories are enabled, we need to disable
+        // auto-transformation to numbers so the strings are intact
+        // for later processing
+
+        var xCategories = series.xaxis.options.mode == "categories",
+            yCategories = series.yaxis.options.mode == "categories";
+        
+        if (!(xCategories || yCategories))
+            return;
+
+        var format = datapoints.format;
+
+        if (!format) {
+            // FIXME: auto-detection should really not be defined here
+            var s = series;
+            format = [];
+            format.push({ x: true, number: true, required: true });
+            format.push({ y: true, number: true, required: true });
+
+            if (s.bars.show || (s.lines.show && s.lines.fill)) {
+                var autoscale = !!((s.bars.show && s.bars.zero) || 
(s.lines.show && s.lines.zero));
+                format.push({ y: true, number: true, required: false, 
defaultValue: 0, autoscale: autoscale });
+                if (s.bars.horizontal) {
+                    delete format[format.length - 1].y;
+                    format[format.length - 1].x = true;
+                }
+            }
+            
+            datapoints.format = format;
+        }
+
+        for (var m = 0; m < format.length; ++m) {
+            if (format[m].x && xCategories)
+                format[m].number = false;
+            
+            if (format[m].y && yCategories)
+                format[m].number = false;
+        }
+    }
+
+    function getNextIndex(categories) {
+        var index = -1;
+        
+        for (var v in categories)
+            if (categories[v] > index)
+                index = categories[v];
+
+        return index + 1;
+    }
+
+    function categoriesTickGenerator(axis) {
+        var res = [];
+        for (var label in axis.categories) {
+            var v = axis.categories[label];
+            if (v >= axis.min && v <= axis.max)
+                res.push([v, label]);
+        }
+
+        res.sort(function (a, b) { return a[0] - b[0]; });
+
+        return res;
+    }
+    
+    function setupCategoriesForAxis(series, axis, datapoints) {
+        if (series[axis].options.mode != "categories")
+            return;
+        
+        if (!series[axis].categories) {
+            // parse options
+            var c = {}, o = series[axis].options.categories || {};
+            if ($.isArray(o)) {
+                for (var i = 0; i < o.length; ++i)
+                    c[o[i]] = i;
+            }
+            else {
+                for (var v in o)
+                    c[v] = o[v];
+            }
+            
+            series[axis].categories = c;
+        }
+
+        // fix ticks
+        if (!series[axis].options.ticks)
+            series[axis].options.ticks = categoriesTickGenerator;
+
+        transformPointsOnAxis(datapoints, axis, series[axis].categories);
+    }
+    
+    function transformPointsOnAxis(datapoints, axis, categories) {
+        // go through the points, transforming them
+        var points = datapoints.points,
+            ps = datapoints.pointsize,
+            format = datapoints.format,
+            formatColumn = axis.charAt(0),
+            index = getNextIndex(categories);
+
+        for (var i = 0; i < points.length; i += ps) {
+            if (points[i] == null)
+                continue;
+            
+            for (var m = 0; m < ps; ++m) {
+                var val = points[i + m];
+
+                if (val == null || !format[m][formatColumn])
+                    continue;
+
+                if (!(val in categories)) {
+                    categories[val] = index;
+                    ++index;
+                }
+                
+                points[i + m] = categories[val];
+            }
+        }
+    }
+
+    function processDatapoints(plot, series, datapoints) {
+        setupCategoriesForAxis(series, "xaxis", datapoints);
+        setupCategoriesForAxis(series, "yaxis", datapoints);
+    }
+
+    function init(plot) {
+        plot.hooks.processRawData.push(processRawData);
+        plot.hooks.processDatapoints.push(processDatapoints);
+    }
+    
+    $.plot.plugins.push({
+        init: init,
+        options: options,
+        name: 'categories',
+        version: '1.0'
+    });
+})(jQuery);

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/7e1546d8/blur-console/src/main/webapp/libs/flot/jquery.flot.crosshair.js
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/libs/flot/jquery.flot.crosshair.js 
b/blur-console/src/main/webapp/libs/flot/jquery.flot.crosshair.js
new file mode 100644
index 0000000..c5df9d9
--- /dev/null
+++ b/blur-console/src/main/webapp/libs/flot/jquery.flot.crosshair.js
@@ -0,0 +1,176 @@
+/* Flot plugin for showing crosshairs when the mouse hovers over the plot.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+The plugin supports these options:
+
+       crosshair: {
+               mode: null or "x" or "y" or "xy"
+               color: color
+               lineWidth: number
+       }
+
+Set the mode to one of "x", "y" or "xy". The "x" mode enables a vertical
+crosshair that lets you trace the values on the x axis, "y" enables a
+horizontal crosshair and "xy" enables them both. "color" is the color of the
+crosshair (default is "rgba(170, 0, 0, 0.80)"), "lineWidth" is the width of
+the drawn lines (default is 1).
+
+The plugin also adds four public methods:
+
+  - setCrosshair( pos )
+
+    Set the position of the crosshair. Note that this is cleared if the user
+    moves the mouse. "pos" is in coordinates of the plot and should be on the
+    form { x: xpos, y: ypos } (you can use x2/x3/... if you're using multiple
+    axes), which is coincidentally the same format as what you get from a
+    "plothover" event. If "pos" is null, the crosshair is cleared.
+
+  - clearCrosshair()
+
+    Clear the crosshair.
+
+  - lockCrosshair(pos)
+
+    Cause the crosshair to lock to the current location, no longer updating if
+    the user moves the mouse. Optionally supply a position (passed on to
+    setCrosshair()) to move it to.
+
+    Example usage:
+
+       var myFlot = $.plot( $("#graph"), ..., { crosshair: { mode: "x" } } };
+       $("#graph").bind( "plothover", function ( evt, position, item ) {
+               if ( item ) {
+                       // Lock the crosshair to the data point being hovered
+                       myFlot.lockCrosshair({
+                               x: item.datapoint[ 0 ],
+                               y: item.datapoint[ 1 ]
+                       });
+               } else {
+                       // Return normal crosshair operation
+                       myFlot.unlockCrosshair();
+               }
+       });
+
+  - unlockCrosshair()
+
+    Free the crosshair to move again after locking it.
+*/
+
+(function ($) {
+    var options = {
+        crosshair: {
+            mode: null, // one of null, "x", "y" or "xy",
+            color: "rgba(170, 0, 0, 0.80)",
+            lineWidth: 1
+        }
+    };
+    
+    function init(plot) {
+        // position of crosshair in pixels
+        var crosshair = { x: -1, y: -1, locked: false };
+
+        plot.setCrosshair = function setCrosshair(pos) {
+            if (!pos)
+                crosshair.x = -1;
+            else {
+                var o = plot.p2c(pos);
+                crosshair.x = Math.max(0, Math.min(o.left, plot.width()));
+                crosshair.y = Math.max(0, Math.min(o.top, plot.height()));
+            }
+            
+            plot.triggerRedrawOverlay();
+        };
+        
+        plot.clearCrosshair = plot.setCrosshair; // passes null for pos
+        
+        plot.lockCrosshair = function lockCrosshair(pos) {
+            if (pos)
+                plot.setCrosshair(pos);
+            crosshair.locked = true;
+        };
+
+        plot.unlockCrosshair = function unlockCrosshair() {
+            crosshair.locked = false;
+        };
+
+        function onMouseOut(e) {
+            if (crosshair.locked)
+                return;
+
+            if (crosshair.x != -1) {
+                crosshair.x = -1;
+                plot.triggerRedrawOverlay();
+            }
+        }
+
+        function onMouseMove(e) {
+            if (crosshair.locked)
+                return;
+                
+            if (plot.getSelection && plot.getSelection()) {
+                crosshair.x = -1; // hide the crosshair while selecting
+                return;
+            }
+                
+            var offset = plot.offset();
+            crosshair.x = Math.max(0, Math.min(e.pageX - offset.left, 
plot.width()));
+            crosshair.y = Math.max(0, Math.min(e.pageY - offset.top, 
plot.height()));
+            plot.triggerRedrawOverlay();
+        }
+        
+        plot.hooks.bindEvents.push(function (plot, eventHolder) {
+            if (!plot.getOptions().crosshair.mode)
+                return;
+
+            eventHolder.mouseout(onMouseOut);
+            eventHolder.mousemove(onMouseMove);
+        });
+
+        plot.hooks.drawOverlay.push(function (plot, ctx) {
+            var c = plot.getOptions().crosshair;
+            if (!c.mode)
+                return;
+
+            var plotOffset = plot.getPlotOffset();
+            
+            ctx.save();
+            ctx.translate(plotOffset.left, plotOffset.top);
+
+            if (crosshair.x != -1) {
+                var adj = plot.getOptions().crosshair.lineWidth % 2 === 0 ? 0 
: 0.5;
+
+                ctx.strokeStyle = c.color;
+                ctx.lineWidth = c.lineWidth;
+                ctx.lineJoin = "round";
+
+                ctx.beginPath();
+                if (c.mode.indexOf("x") != -1) {
+                    var drawX = Math.round(crosshair.x) + adj;
+                    ctx.moveTo(drawX, 0);
+                    ctx.lineTo(drawX, plot.height());
+                }
+                if (c.mode.indexOf("y") != -1) {
+                    var drawY = Math.round(crosshair.y) + adj;
+                    ctx.moveTo(0, drawY);
+                    ctx.lineTo(plot.width(), drawY);
+                }
+                ctx.stroke();
+            }
+            ctx.restore();
+        });
+
+        plot.hooks.shutdown.push(function (plot, eventHolder) {
+            eventHolder.unbind("mouseout", onMouseOut);
+            eventHolder.unbind("mousemove", onMouseMove);
+        });
+    }
+    
+    $.plot.plugins.push({
+        init: init,
+        options: options,
+        name: 'crosshair',
+        version: '1.0'
+    });
+})(jQuery);

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/7e1546d8/blur-console/src/main/webapp/libs/flot/jquery.flot.errorbars.js
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/libs/flot/jquery.flot.errorbars.js 
b/blur-console/src/main/webapp/libs/flot/jquery.flot.errorbars.js
new file mode 100644
index 0000000..7298436
--- /dev/null
+++ b/blur-console/src/main/webapp/libs/flot/jquery.flot.errorbars.js
@@ -0,0 +1,353 @@
+/* Flot plugin for plotting error bars.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+Error bars are used to show standard deviation and other statistical
+properties in a plot.
+
+* Created by Rui Pereira  -  rui (dot) pereira (at) gmail (dot) com
+
+This plugin allows you to plot error-bars over points. Set "errorbars" inside
+the points series to the axis name over which there will be error values in
+your data array (*even* if you do not intend to plot them later, by setting
+"show: null" on xerr/yerr).
+
+The plugin supports these options:
+
+       series: {
+               points: {
+                       errorbars: "x" or "y" or "xy",
+                       xerr: {
+                               show: null/false or true,
+                               asymmetric: null/false or true,
+                               upperCap: null or "-" or function,
+                               lowerCap: null or "-" or function,
+                               color: null or color,
+                               radius: null or number
+                       },
+                       yerr: { same options as xerr }
+               }
+       }
+
+Each data point array is expected to be of the type:
+
+       "x"  [ x, y, xerr ]
+       "y"  [ x, y, yerr ]
+       "xy" [ x, y, xerr, yerr ]
+
+Where xerr becomes xerr_lower,xerr_upper for the asymmetric error case, and
+equivalently for yerr. Eg., a datapoint for the "xy" case with symmetric
+error-bars on X and asymmetric on Y would be:
+
+       [ x, y, xerr, yerr_lower, yerr_upper ]
+
+By default no end caps are drawn. Setting upperCap and/or lowerCap to "-" will
+draw a small cap perpendicular to the error bar. They can also be set to a
+user-defined drawing function, with (ctx, x, y, radius) as parameters, as eg.
+
+       function drawSemiCircle( ctx, x, y, radius ) {
+               ctx.beginPath();
+               ctx.arc( x, y, radius, 0, Math.PI, false );
+               ctx.moveTo( x - radius, y );
+               ctx.lineTo( x + radius, y );
+               ctx.stroke();
+       }
+
+Color and radius both default to the same ones of the points series if not
+set. The independent radius parameter on xerr/yerr is useful for the case when
+we may want to add error-bars to a line, without showing the interconnecting
+points (with radius: 0), and still showing end caps on the error-bars.
+shadowSize and lineWidth are derived as well from the points series.
+
+*/
+
+(function ($) {
+    var options = {
+        series: {
+            points: {
+                errorbars: null, //should be 'x', 'y' or 'xy'
+                xerr: { err: 'x', show: null, asymmetric: null, upperCap: 
null, lowerCap: null, color: null, radius: null},
+                yerr: { err: 'y', show: null, asymmetric: null, upperCap: 
null, lowerCap: null, color: null, radius: null}
+            }
+        }
+    };
+
+    function processRawData(plot, series, data, datapoints){
+        if (!series.points.errorbars)
+            return;
+
+        // x,y values
+        var format = [
+            { x: true, number: true, required: true },
+            { y: true, number: true, required: true }
+        ];
+
+        var errors = series.points.errorbars;
+        // error bars - first X then Y
+        if (errors == 'x' || errors == 'xy') {
+            // lower / upper error
+            if (series.points.xerr.asymmetric) {
+                format.push({ x: true, number: true, required: true });
+                format.push({ x: true, number: true, required: true });
+            } else
+                format.push({ x: true, number: true, required: true });
+        }
+        if (errors == 'y' || errors == 'xy') {
+            // lower / upper error
+            if (series.points.yerr.asymmetric) {
+                format.push({ y: true, number: true, required: true });
+                format.push({ y: true, number: true, required: true });
+            } else
+                format.push({ y: true, number: true, required: true });
+        }
+        datapoints.format = format;
+    }
+
+    function parseErrors(series, i){
+
+        var points = series.datapoints.points;
+
+        // read errors from points array
+        var exl = null,
+                exu = null,
+                eyl = null,
+                eyu = null;
+        var xerr = series.points.xerr,
+                yerr = series.points.yerr;
+
+        var eb = series.points.errorbars;
+        // error bars - first X
+        if (eb == 'x' || eb == 'xy') {
+            if (xerr.asymmetric) {
+                exl = points[i + 2];
+                exu = points[i + 3];
+                if (eb == 'xy')
+                    if (yerr.asymmetric){
+                        eyl = points[i + 4];
+                        eyu = points[i + 5];
+                    } else eyl = points[i + 4];
+            } else {
+                exl = points[i + 2];
+                if (eb == 'xy')
+                    if (yerr.asymmetric) {
+                        eyl = points[i + 3];
+                        eyu = points[i + 4];
+                    } else eyl = points[i + 3];
+            }
+        // only Y
+        } else if (eb == 'y')
+            if (yerr.asymmetric) {
+                eyl = points[i + 2];
+                eyu = points[i + 3];
+            } else eyl = points[i + 2];
+
+        // symmetric errors?
+        if (exu == null) exu = exl;
+        if (eyu == null) eyu = eyl;
+
+        var errRanges = [exl, exu, eyl, eyu];
+        // nullify if not showing
+        if (!xerr.show){
+            errRanges[0] = null;
+            errRanges[1] = null;
+        }
+        if (!yerr.show){
+            errRanges[2] = null;
+            errRanges[3] = null;
+        }
+        return errRanges;
+    }
+
+    function drawSeriesErrors(plot, ctx, s){
+
+        var points = s.datapoints.points,
+                ps = s.datapoints.pointsize,
+                ax = [s.xaxis, s.yaxis],
+                radius = s.points.radius,
+                err = [s.points.xerr, s.points.yerr];
+
+        //sanity check, in case some inverted axis hack is applied to flot
+        var invertX = false;
+        if (ax[0].p2c(ax[0].max) < ax[0].p2c(ax[0].min)) {
+            invertX = true;
+            var tmp = err[0].lowerCap;
+            err[0].lowerCap = err[0].upperCap;
+            err[0].upperCap = tmp;
+        }
+
+        var invertY = false;
+        if (ax[1].p2c(ax[1].min) < ax[1].p2c(ax[1].max)) {
+            invertY = true;
+            var tmp = err[1].lowerCap;
+            err[1].lowerCap = err[1].upperCap;
+            err[1].upperCap = tmp;
+        }
+
+        for (var i = 0; i < s.datapoints.points.length; i += ps) {
+
+            //parse
+            var errRanges = parseErrors(s, i);
+
+            //cycle xerr & yerr
+            for (var e = 0; e < err.length; e++){
+
+                var minmax = [ax[e].min, ax[e].max];
+
+                //draw this error?
+                if (errRanges[e * err.length]){
+
+                    //data coordinates
+                    var x = points[i],
+                        y = points[i + 1];
+
+                    //errorbar ranges
+                    var upper = [x, y][e] + errRanges[e * err.length + 1],
+                        lower = [x, y][e] - errRanges[e * err.length];
+
+                    //points outside of the canvas
+                    if (err[e].err == 'x')
+                        if (y > ax[1].max || y < ax[1].min || upper < 
ax[0].min || lower > ax[0].max)
+                            continue;
+                    if (err[e].err == 'y')
+                        if (x > ax[0].max || x < ax[0].min || upper < 
ax[1].min || lower > ax[1].max)
+                            continue;
+
+                    // prevent errorbars getting out of the canvas
+                    var drawUpper = true,
+                        drawLower = true;
+
+                    if (upper > minmax[1]) {
+                        drawUpper = false;
+                        upper = minmax[1];
+                    }
+                    if (lower < minmax[0]) {
+                        drawLower = false;
+                        lower = minmax[0];
+                    }
+
+                    //sanity check, in case some inverted axis hack is applied 
to flot
+                    if ((err[e].err == 'x' && invertX) || (err[e].err == 'y' 
&& invertY)) {
+                        //swap coordinates
+                        var tmp = lower;
+                        lower = upper;
+                        upper = tmp;
+                        tmp = drawLower;
+                        drawLower = drawUpper;
+                        drawUpper = tmp;
+                        tmp = minmax[0];
+                        minmax[0] = minmax[1];
+                        minmax[1] = tmp;
+                    }
+
+                    // convert to pixels
+                    x = ax[0].p2c(x),
+                        y = ax[1].p2c(y),
+                        upper = ax[e].p2c(upper);
+                    lower = ax[e].p2c(lower);
+                    minmax[0] = ax[e].p2c(minmax[0]);
+                    minmax[1] = ax[e].p2c(minmax[1]);
+
+                    //same style as points by default
+                    var lw = err[e].lineWidth ? err[e].lineWidth : 
s.points.lineWidth,
+                        sw = s.points.shadowSize != null ? s.points.shadowSize 
: s.shadowSize;
+
+                    //shadow as for points
+                    if (lw > 0 && sw > 0) {
+                        var w = sw / 2;
+                        ctx.lineWidth = w;
+                        ctx.strokeStyle = "rgba(0,0,0,0.1)";
+                        drawError(ctx, err[e], x, y, upper, lower, drawUpper, 
drawLower, radius, w + w/2, minmax);
+
+                        ctx.strokeStyle = "rgba(0,0,0,0.2)";
+                        drawError(ctx, err[e], x, y, upper, lower, drawUpper, 
drawLower, radius, w/2, minmax);
+                    }
+
+                    ctx.strokeStyle = err[e].color? err[e].color: s.color;
+                    ctx.lineWidth = lw;
+                    //draw it
+                    drawError(ctx, err[e], x, y, upper, lower, drawUpper, 
drawLower, radius, 0, minmax);
+                }
+            }
+        }
+    }
+
+    function 
drawError(ctx,err,x,y,upper,lower,drawUpper,drawLower,radius,offset,minmax){
+
+        //shadow offset
+        y += offset;
+        upper += offset;
+        lower += offset;
+
+        // error bar - avoid plotting over circles
+        if (err.err == 'x'){
+            if (upper > x + radius) drawPath(ctx, [[upper,y],[Math.max(x + 
radius,minmax[0]),y]]);
+            else drawUpper = false;
+            if (lower < x - radius) drawPath(ctx, [[Math.min(x - 
radius,minmax[1]),y],[lower,y]] );
+            else drawLower = false;
+        }
+        else {
+            if (upper < y - radius) drawPath(ctx, [[x,upper],[x,Math.min(y - 
radius,minmax[0])]] );
+            else drawUpper = false;
+            if (lower > y + radius) drawPath(ctx, [[x,Math.max(y + 
radius,minmax[1])],[x,lower]] );
+            else drawLower = false;
+        }
+
+        //internal radius value in errorbar, allows to plot radius 0 points 
and still keep proper sized caps
+        //this is a way to get errorbars on lines without visible connecting 
dots
+        radius = err.radius != null? err.radius: radius;
+
+        // upper cap
+        if (drawUpper) {
+            if (err.upperCap == '-'){
+                if (err.err=='x') drawPath(ctx, [[upper,y - radius],[upper,y + 
radius]] );
+                else drawPath(ctx, [[x - radius,upper],[x + radius,upper]] );
+            } else if ($.isFunction(err.upperCap)){
+                if (err.err=='x') err.upperCap(ctx, upper, y, radius);
+                else err.upperCap(ctx, x, upper, radius);
+            }
+        }
+        // lower cap
+        if (drawLower) {
+            if (err.lowerCap == '-'){
+                if (err.err=='x') drawPath(ctx, [[lower,y - radius],[lower,y + 
radius]] );
+                else drawPath(ctx, [[x - radius,lower],[x + radius,lower]] );
+            } else if ($.isFunction(err.lowerCap)){
+                if (err.err=='x') err.lowerCap(ctx, lower, y, radius);
+                else err.lowerCap(ctx, x, lower, radius);
+            }
+        }
+    }
+
+    function drawPath(ctx, pts){
+        ctx.beginPath();
+        ctx.moveTo(pts[0][0], pts[0][1]);
+        for (var p=1; p < pts.length; p++)
+            ctx.lineTo(pts[p][0], pts[p][1]);
+        ctx.stroke();
+    }
+
+    function draw(plot, ctx){
+        var plotOffset = plot.getPlotOffset();
+
+        ctx.save();
+        ctx.translate(plotOffset.left, plotOffset.top);
+        $.each(plot.getData(), function (i, s) {
+            if (s.points.errorbars && (s.points.xerr.show || 
s.points.yerr.show))
+                drawSeriesErrors(plot, ctx, s);
+        });
+        ctx.restore();
+    }
+
+    function init(plot) {
+        plot.hooks.processRawData.push(processRawData);
+        plot.hooks.draw.push(draw);
+    }
+
+    $.plot.plugins.push({
+                init: init,
+                options: options,
+                name: 'errorbars',
+                version: '1.0'
+            });
+})(jQuery);

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/7e1546d8/blur-console/src/main/webapp/libs/flot/jquery.flot.fillbetween.js
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/libs/flot/jquery.flot.fillbetween.js 
b/blur-console/src/main/webapp/libs/flot/jquery.flot.fillbetween.js
new file mode 100644
index 0000000..2854d2d
--- /dev/null
+++ b/blur-console/src/main/webapp/libs/flot/jquery.flot.fillbetween.js
@@ -0,0 +1,226 @@
+/* Flot plugin for computing bottoms for filled line and bar charts.
+
+Copyright (c) 2007-2013 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);

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/7e1546d8/blur-console/src/main/webapp/libs/flot/jquery.flot.image.js
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/libs/flot/jquery.flot.image.js 
b/blur-console/src/main/webapp/libs/flot/jquery.flot.image.js
new file mode 100644
index 0000000..d2837cf
--- /dev/null
+++ b/blur-console/src/main/webapp/libs/flot/jquery.flot.image.js
@@ -0,0 +1,241 @@
+/* Flot plugin for plotting images.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+The data syntax is [ [ image, x1, y1, x2, y2 ], ... ] where (x1, y1) and
+(x2, y2) are where you intend the two opposite corners of the image to end up
+in the plot. Image must be a fully loaded Javascript image (you can make one
+with new Image()). If the image is not complete, it's skipped when plotting.
+
+There are two helpers included for retrieving images. The easiest work the way
+that you put in URLs instead of images in the data, like this:
+
+       [ "myimage.png", 0, 0, 10, 10 ]
+
+Then call $.plot.image.loadData( data, options, callback ) where data and
+options are the same as you pass in to $.plot. This loads the images, replaces
+the URLs in the data with the corresponding images and calls "callback" when
+all images are loaded (or failed loading). In the callback, you can then call
+$.plot with the data set. See the included example.
+
+A more low-level helper, $.plot.image.load(urls, callback) is also included.
+Given a list of URLs, it calls callback with an object mapping from URL to
+Image object when all images are loaded or have failed loading.
+
+The plugin supports these options:
+
+       series: {
+               images: {
+                       show: boolean
+                       anchor: "corner" or "center"
+                       alpha: [ 0, 1 ]
+               }
+       }
+
+They can be specified for a specific series:
+
+       $.plot( $("#placeholder"), [{
+               data: [ ... ],
+               images: { ... }
+       ])
+
+Note that because the data format is different from usual data points, you
+can't use images with anything else in a specific data series.
+
+Setting "anchor" to "center" causes the pixels in the image to be anchored at
+the corner pixel centers inside of at the pixel corners, effectively letting
+half a pixel stick out to each side in the plot.
+
+A possible future direction could be support for tiling for large images (like
+Google Maps).
+
+*/
+
+(function ($) {
+    var options = {
+        series: {
+            images: {
+                show: false,
+                alpha: 1,
+                anchor: "corner" // or "center"
+            }
+        }
+    };
+
+    $.plot.image = {};
+
+    $.plot.image.loadDataImages = function (series, options, callback) {
+        var urls = [], points = [];
+
+        var defaultShow = options.series.images.show;
+        
+        $.each(series, function (i, s) {
+            if (!(defaultShow || s.images.show))
+                return;
+            
+            if (s.data)
+                s = s.data;
+
+            $.each(s, function (i, p) {
+                if (typeof p[0] == "string") {
+                    urls.push(p[0]);
+                    points.push(p);
+                }
+            });
+        });
+
+        $.plot.image.load(urls, function (loadedImages) {
+            $.each(points, function (i, p) {
+                var url = p[0];
+                if (loadedImages[url])
+                    p[0] = loadedImages[url];
+            });
+
+            callback();
+        });
+    }
+    
+    $.plot.image.load = function (urls, callback) {
+        var missing = urls.length, loaded = {};
+        if (missing == 0)
+            callback({});
+
+        $.each(urls, function (i, url) {
+            var handler = function () {
+                --missing;
+                
+                loaded[url] = this;
+                
+                if (missing == 0)
+                    callback(loaded);
+            };
+
+            $('<img />').load(handler).error(handler).attr('src', url);
+        });
+    };
+    
+    function drawSeries(plot, ctx, series) {
+        var plotOffset = plot.getPlotOffset();
+        
+        if (!series.images || !series.images.show)
+            return;
+        
+        var points = series.datapoints.points,
+            ps = series.datapoints.pointsize;
+        
+        for (var i = 0; i < points.length; i += ps) {
+            var img = points[i],
+                x1 = points[i + 1], y1 = points[i + 2],
+                x2 = points[i + 3], y2 = points[i + 4],
+                xaxis = series.xaxis, yaxis = series.yaxis,
+                tmp;
+
+            // actually we should check img.complete, but it
+            // appears to be a somewhat unreliable indicator in
+            // IE6 (false even after load event)
+            if (!img || img.width <= 0 || img.height <= 0)
+                continue;
+
+            if (x1 > x2) {
+                tmp = x2;
+                x2 = x1;
+                x1 = tmp;
+            }
+            if (y1 > y2) {
+                tmp = y2;
+                y2 = y1;
+                y1 = tmp;
+            }
+            
+            // if the anchor is at the center of the pixel, expand the 
+            // image by 1/2 pixel in each direction
+            if (series.images.anchor == "center") {
+                tmp = 0.5 * (x2-x1) / (img.width - 1);
+                x1 -= tmp;
+                x2 += tmp;
+                tmp = 0.5 * (y2-y1) / (img.height - 1);
+                y1 -= tmp;
+                y2 += tmp;
+            }
+            
+            // clip
+            if (x1 == x2 || y1 == y2 ||
+                x1 >= xaxis.max || x2 <= xaxis.min ||
+                y1 >= yaxis.max || y2 <= yaxis.min)
+                continue;
+
+            var sx1 = 0, sy1 = 0, sx2 = img.width, sy2 = img.height;
+            if (x1 < xaxis.min) {
+                sx1 += (sx2 - sx1) * (xaxis.min - x1) / (x2 - x1);
+                x1 = xaxis.min;
+            }
+
+            if (x2 > xaxis.max) {
+                sx2 += (sx2 - sx1) * (xaxis.max - x2) / (x2 - x1);
+                x2 = xaxis.max;
+            }
+
+            if (y1 < yaxis.min) {
+                sy2 += (sy1 - sy2) * (yaxis.min - y1) / (y2 - y1);
+                y1 = yaxis.min;
+            }
+
+            if (y2 > yaxis.max) {
+                sy1 += (sy1 - sy2) * (yaxis.max - y2) / (y2 - y1);
+                y2 = yaxis.max;
+            }
+            
+            x1 = xaxis.p2c(x1);
+            x2 = xaxis.p2c(x2);
+            y1 = yaxis.p2c(y1);
+            y2 = yaxis.p2c(y2);
+            
+            // the transformation may have swapped us
+            if (x1 > x2) {
+                tmp = x2;
+                x2 = x1;
+                x1 = tmp;
+            }
+            if (y1 > y2) {
+                tmp = y2;
+                y2 = y1;
+                y1 = tmp;
+            }
+
+            tmp = ctx.globalAlpha;
+            ctx.globalAlpha *= series.images.alpha;
+            ctx.drawImage(img,
+                          sx1, sy1, sx2 - sx1, sy2 - sy1,
+                          x1 + plotOffset.left, y1 + plotOffset.top,
+                          x2 - x1, y2 - y1);
+            ctx.globalAlpha = tmp;
+        }
+    }
+
+    function processRawData(plot, series, data, datapoints) {
+        if (!series.images.show)
+            return;
+
+        // format is Image, x1, y1, x2, y2 (opposite corners)
+        datapoints.format = [
+            { required: true },
+            { x: true, number: true, required: true },
+            { y: true, number: true, required: true },
+            { x: true, number: true, required: true },
+            { y: true, number: true, required: true }
+        ];
+    }
+    
+    function init(plot) {
+        plot.hooks.processRawData.push(processRawData);
+        plot.hooks.drawSeries.push(drawSeries);
+    }
+    
+    $.plot.plugins.push({
+        init: init,
+        options: options,
+        name: 'image',
+        version: '1.1'
+    });
+})(jQuery);

Reply via email to