|
(function (root, factory) { |
|
if (typeof define === 'function' && define.amd) { |
|
// AMD. Register as an anonymous module. |
|
define(['bean', 'underscore'], function (bean, _) { |
|
// Also create a global in case some scripts |
|
// that are loaded still are looking for |
|
// a global even when an AMD loader is in use. |
|
return (root.Flotr = factory(bean, _)); |
|
}); |
|
} else { |
|
// Browser globals |
|
root.Flotr = factory(root.bean, root._); |
|
} |
|
}(this, function (bean, _) { |
|
|
|
/** |
|
* Flotr2 (c) 2012 Carl Sutherland |
|
* MIT License |
|
* Special thanks to: |
|
* Flotr: http://code.google.com/p/flotr/ (fork) |
|
* Flot: https://github.com/flot/flot (original fork) |
|
*/ |
|
(function () { |
|
|
|
var |
|
global = this, |
|
previousFlotr = this.Flotr, |
|
Flotr; |
|
|
|
Flotr = { |
|
_: _, |
|
bean: bean, |
|
isIphone: /iphone/i.test(navigator.userAgent), |
|
isIE: (navigator.appVersion.indexOf("MSIE") != -1 ? parseFloat(navigator.appVersion.split("MSIE")[1]) : false), |
|
|
|
/** |
|
* An object of the registered graph types. Use Flotr.addType(type, object) |
|
* to add your own type. |
|
*/ |
|
graphTypes: {}, |
|
|
|
/** |
|
* The list of the registered plugins |
|
*/ |
|
plugins: {}, |
|
|
|
/** |
|
* Can be used to add your own chart type. |
|
* @param {String} name - Type of chart, like 'pies', 'bars' etc. |
|
* @param {String} graphType - The object containing the basic drawing functions (draw, etc) |
|
*/ |
|
addType: function(name, graphType){ |
|
Flotr.graphTypes[name] = graphType; |
|
Flotr.defaultOptions[name] = graphType.options || {}; |
|
Flotr.defaultOptions.defaultType = Flotr.defaultOptions.defaultType || name; |
|
}, |
|
|
|
/** |
|
* Can be used to add a plugin |
|
* @param {String} name - The name of the plugin |
|
* @param {String} plugin - The object containing the plugin's data (callbacks, options, function1, function2, ...) |
|
*/ |
|
addPlugin: function(name, plugin){ |
|
Flotr.plugins[name] = plugin; |
|
Flotr.defaultOptions[name] = plugin.options || {}; |
|
}, |
|
|
|
/** |
|
* Draws the graph. This function is here for backwards compatibility with Flotr version 0.1.0alpha. |
|
* You could also draw graphs by directly calling Flotr.Graph(element, data, options). |
|
* @param {Element} el - element to insert the graph into |
|
* @param {Object} data - an array or object of dataseries |
|
* @param {Object} options - an object containing options |
|
* @param {Class} _GraphKlass_ - (optional) Class to pass the arguments to, defaults to Flotr.Graph |
|
* @return {Object} returns a new graph object and of course draws the graph. |
|
*/ |
|
draw: function(el, data, options, GraphKlass){ |
|
GraphKlass = GraphKlass || Flotr.Graph; |
|
return new GraphKlass(el, data, options); |
|
}, |
|
|
|
/** |
|
* Recursively merges two objects. |
|
* @param {Object} src - source object (likely the object with the least properties) |
|
* @param {Object} dest - destination object (optional, object with the most properties) |
|
* @return {Object} recursively merged Object |
|
* @TODO See if we can't remove this. |
|
*/ |
|
merge: function(src, dest){ |
|
var i, v, result = dest || {}; |
|
|
|
for (i in src) { |
|
v = src[i]; |
|
if (v && typeof(v) === 'object') { |
|
if (v.constructor === Array) { |
|
result[i] = this._.clone(v); |
|
} else if (v.constructor !== RegExp && !this._.isElement(v)) { |
|
result[i] = Flotr.merge(v, (dest ? dest[i] : undefined)); |
|
} else { |
|
result[i] = v; |
|
} |
|
} else { |
|
result[i] = v; |
|
} |
|
} |
|
|
|
return result; |
|
}, |
|
|
|
/** |
|
* Recursively clones an object. |
|
* @param {Object} object - The object to clone |
|
* @return {Object} the clone |
|
* @TODO See if we can't remove this. |
|
*/ |
|
clone: function(object){ |
|
return Flotr.merge(object, {}); |
|
}, |
|
|
|
/** |
|
* Function calculates the ticksize and returns it. |
|
* @param {Integer} noTicks - number of ticks |
|
* @param {Integer} min - lower bound integer value for the current axis |
|
* @param {Integer} max - upper bound integer value for the current axis |
|
* @param {Integer} decimals - number of decimals for the ticks |
|
* @return {Integer} returns the ticksize in pixels |
|
*/ |
|
getTickSize: function(noTicks, min, max, decimals){ |
|
var delta = (max - min) / noTicks, |
|
magn = Flotr.getMagnitude(delta), |
|
tickSize = 10, |
|
norm = delta / magn; // Norm is between 1.0 and 10.0. |
|
|
|
if(norm < 1.5) tickSize = 1; |
|
else if(norm < 2.25) tickSize = 2; |
|
else if(norm < 3) tickSize = ((decimals === 0) ? 2 : 2.5); |
|
else if(norm < 7.5) tickSize = 5; |
|
|
|
return tickSize * magn; |
|
}, |
|
|
|
/** |
|
* Default tick formatter. |
|
* @param {String, Integer} val - tick value integer |
|
* @param {Object} axisOpts - the axis' options |
|
* @return {String} formatted tick string |
|
*/ |
|
defaultTickFormatter: function(val, axisOpts){ |
|
return val+''; |
|
}, |
|
|
|
/** |
|
* Formats the mouse tracker values. |
|
* @param {Object} obj - Track value Object {x:..,y:..} |
|
* @return {String} Formatted track string |
|
*/ |
|
defaultTrackFormatter: function(obj){ |
|
return '('+obj.x+', '+obj.y+')'; |
|
}, |
|
|
|
/** |
|
* Utility function to convert file size values in bytes to kB, MB, ... |
|
* @param value {Number} - The value to convert |
|
* @param precision {Number} - The number of digits after the comma (default: 2) |
|
* @param base {Number} - The base (default: 1000) |
|
*/ |
|
engineeringNotation: function(value, precision, base){ |
|
var sizes = ['Y','Z','E','P','T','G','M','k',''], |
|
fractionSizes = ['y','z','a','f','p','n','µ','m',''], |
|
total = sizes.length; |
|
|
|
base = base || 1000; |
|
precision = Math.pow(10, precision || 2); |
|
|
|
if (value === 0) return 0; |
|
|
|
if (value > 1) { |
|
while (total-- && (value >= base)) value /= base; |
|
} |
|
else { |
|
sizes = fractionSizes; |
|
total = sizes.length; |
|
while (total-- && (value < 1)) value *= base; |
|
} |
|
|
|
return (Math.round(value * precision) / precision) + sizes[total]; |
|
}, |
|
|
|
/** |
|
* Returns the magnitude of the input value. |
|
* @param {Integer, Float} x - integer or float value |
|
* @return {Integer, Float} returns the magnitude of the input value |
|
*/ |
|
getMagnitude: function(x){ |
|
return Math.pow(10, Math.floor(Math.log(x) / Math.LN10)); |
|
}, |
|
toPixel: function(val){ |
|
return Math.floor(val)+0.5;//((val-Math.round(val) < 0.4) ? (Math.floor(val)-0.5) : val); |
|
}, |
|
toRad: function(angle){ |
|
return -angle * (Math.PI/180); |
|
}, |
|
floorInBase: function(n, base) { |
|
return base * Math.floor(n / base); |
|
}, |
|
drawText: function(ctx, text, x, y, style) { |
|
if (!ctx.fillText) { |
|
ctx.drawText(text, x, y, style); |
|
return; |
|
} |
|
|
|
style = this._.extend({ |
|
size: Flotr.defaultOptions.fontSize, |
|
color: '#000000', |
|
textAlign: 'left', |
|
textBaseline: 'bottom', |
|
weight: 1, |
|
angle: 0 |
|
}, style); |
|
|
|
ctx.save(); |
|
ctx.translate(x, y); |
|
ctx.rotate(style.angle); |
|
ctx.fillStyle = style.color; |
|
ctx.font = (style.weight > 1 ? "bold " : "") + (style.size*1.3) + "px sans-serif"; |
|
ctx.textAlign = style.textAlign; |
|
ctx.textBaseline = style.textBaseline; |
|
ctx.fillText(text, 0, 0); |
|
ctx.restore(); |
|
}, |
|
getBestTextAlign: function(angle, style) { |
|
style = style || {textAlign: 'center', textBaseline: 'middle'}; |
|
angle += Flotr.getTextAngleFromAlign(style); |
|
|
|
if (Math.abs(Math.cos(angle)) > 10e-3) |
|
style.textAlign = (Math.cos(angle) > 0 ? 'right' : 'left'); |
|
|
|
if (Math.abs(Math.sin(angle)) > 10e-3) |
|
style.textBaseline = (Math.sin(angle) > 0 ? 'top' : 'bottom'); |
|
|
|
return style; |
|
}, |
|
alignTable: { |
|
'right middle' : 0, |
|
'right top' : Math.PI/4, |
|
'center top' : Math.PI/2, |
|
'left top' : 3*(Math.PI/4), |
|
'left middle' : Math.PI, |
|
'left bottom' : -3*(Math.PI/4), |
|
'center bottom': -Math.PI/2, |
|
'right bottom' : -Math.PI/4, |
|
'center middle': 0 |
|
}, |
|
getTextAngleFromAlign: function(style) { |
|
return Flotr.alignTable[style.textAlign+' '+style.textBaseline] || 0; |
|
}, |
|
noConflict : function () { |
|
global.Flotr = previousFlotr; |
|
return this; |
|
} |
|
}; |
|
|
|
global.Flotr = Flotr; |
|
|
|
})(); |
|
|
|
/** |
|
* Flotr Defaults |
|
*/ |
|
Flotr.defaultOptions = { |
|
colors: ['#00A8F0', '#C0D800', '#CB4B4B', '#4DA74D', '#9440ED'], //=> The default colorscheme. When there are > 5 series, additional colors are generated. |
|
ieBackgroundColor: '#FFFFFF', // Background color for excanvas clipping |
|
title: null, // => The graph's title |
|
subtitle: null, // => The graph's subtitle |
|
shadowSize: 4, // => size of the 'fake' shadow |
|
defaultType: null, // => default series type |
|
HtmlText: true, // => wether to draw the text using HTML or on the canvas |
|
fontColor: '#545454', // => default font color |
|
fontSize: 7.5, // => canvas' text font size |
|
resolution: 1, // => resolution of the graph, to have printer-friendly graphs ! |
|
parseFloat: true, // => whether to preprocess data for floats (ie. if input is string) |
|
preventDefault: true, // => preventDefault by default for mobile events. Turn off to enable scroll. |
|
xaxis: { |
|
ticks: null, // => format: either [1, 3] or [[1, 'a'], 3] |
|
minorTicks: null, // => format: either [1, 3] or [[1, 'a'], 3] |
|
showLabels: true, // => setting to true will show the axis ticks labels, hide otherwise |
|
showMinorLabels: false,// => true to show the axis minor ticks labels, false to hide |
|
labelsAngle: 0, // => labels' angle, in degrees |
|
title: null, // => axis title |
|
titleAngle: 0, // => axis title's angle, in degrees |
|
noTicks: 5, // => number of ticks for automagically generated ticks |
|
minorTickFreq: null, // => number of minor ticks between major ticks for autogenerated ticks |
|
tickFormatter: Flotr.defaultTickFormatter, // => fn: number, Object -> string |
|
tickDecimals: null, // => no. of decimals, null means auto |
|
min: null, // => min. value to show, null means set automatically |
|
max: null, // => max. value to show, null means set automatically |
|
autoscale: false, // => Turns autoscaling on with true |
|
autoscaleMargin: 0, // => margin in % to add if auto-setting min/max |
|
color: null, // => color of the ticks |
|
mode: 'normal', // => can be 'time' or 'normal' |
|
timeFormat: null, |
|
timeMode:'UTC', // => For UTC time ('local' for local time). |
|
timeUnit:'millisecond',// => Unit for time (millisecond, second, minute, hour, day, month, year) |
|
scaling: 'linear', // => Scaling, can be 'linear' or 'logarithmic' |
|
base: Math.E, |
|
titleAlign: 'center', |
|
margin: true // => Turn off margins with false |
|
}, |
|
x2axis: {}, |
|
yaxis: { |
|
ticks: null, // => format: either [1, 3] or [[1, 'a'], 3] |
|
minorTicks: null, // => format: either [1, 3] or [[1, 'a'], 3] |
|
showLabels: true, // => setting to true will show the axis ticks labels, hide otherwise |
|
showMinorLabels: false,// => true to show the axis minor ticks labels, false to hide |
|
labelsAngle: 0, // => labels' angle, in degrees |
|
title: null, // => axis title |
|
titleAngle: 90, // => axis title's angle, in degrees |
|
noTicks: 5, // => number of ticks for automagically generated ticks |
|
minorTickFreq: null, // => number of minor ticks between major ticks for autogenerated ticks |
|
tickFormatter: Flotr.defaultTickFormatter, // => fn: number, Object -> string |
|
tickDecimals: null, // => no. of decimals, null means auto |
|
min: null, // => min. value to show, null means set automatically |
|
max: null, // => max. value to show, null means set automatically |
|
autoscale: false, // => Turns autoscaling on with true |
|
autoscaleMargin: 0, // => margin in % to add if auto-setting min/max |
|
color: null, // => The color of the ticks |
|
scaling: 'linear', // => Scaling, can be 'linear' or 'logarithmic' |
|
base: Math.E, |
|
titleAlign: 'center', |
|
margin: true // => Turn off margins with false |
|
}, |
|
y2axis: { |
|
titleAngle: 270 |
|
}, |
|
grid: { |
|
color: '#545454', // => primary color used for outline and labels |
|
backgroundColor: null, // => null for transparent, else color |
|
backgroundImage: null, // => background image. String or object with src, left and top |
|
watermarkAlpha: 0.4, // => |
|
tickColor: '#DDDDDD', // => color used for the ticks |
|
labelMargin: 3, // => margin in pixels |
|
verticalLines: true, // => whether to show gridlines in vertical direction |
|
minorVerticalLines: null, // => whether to show gridlines for minor ticks in vertical dir. |
|
horizontalLines: true, // => whether to show gridlines in horizontal direction |
|
minorHorizontalLines: null, // => whether to show gridlines for minor ticks in horizontal dir. |
|
outlineWidth: 1, // => width of the grid outline/border in pixels |
|
outline : 'nsew', // => walls of the outline to display |
|
circular: false // => if set to true, the grid will be circular, must be used when radars are drawn |
|
}, |
|
mouse: { |
|
track: false, // => true to track the mouse, no tracking otherwise |
|
trackAll: false, |
|
position: 'se', // => position of the value box (default south-east) |
|
relative: false, // => next to the mouse cursor |
|
trackFormatter: Flotr.defaultTrackFormatter, // => formats the values in the value box |
|
margin: 5, // => margin in pixels of the valuebox |
|
lineColor: '#FF3F19', // => line color of points that are drawn when mouse comes near a value of a series |
|
trackDecimals: 1, // => decimals for the track values |
|
sensibility: 2, // => the lower this number, the more precise you have to aim to show a value |
|
trackY: true, // => whether or not to track the mouse in the y axis |
|
radius: 3, // => radius of the track point |
|
fillCo |