--- /dev/null
+
+
+Dygraph.LOG_SCALE = 10;
+Dygraph.LN_TEN = Math.log(Dygraph.LOG_SCALE);
+
+/** @private */
+Dygraph.log10 = function(x) {
+ return Math.log(x) / Dygraph.LN_TEN;
+}
+
+// Various logging levels.
+Dygraph.DEBUG = 1;
+Dygraph.INFO = 2;
+Dygraph.WARNING = 3;
+Dygraph.ERROR = 3;
+
+// TODO(danvk): any way I can get the line numbers to be this.warn call?
+/**
+ * @private
+ * Log an error on the JS console at the given severity.
+ * @param { Integer } severity One of Dygraph.{DEBUG,INFO,WARNING,ERROR}
+ * @param { String } The message to log.
+ */
+Dygraph.log = function(severity, message) {
+ if (typeof(console) != 'undefined') {
+ switch (severity) {
+ case Dygraph.DEBUG:
+ console.debug('dygraphs: ' + message);
+ break;
+ case Dygraph.INFO:
+ console.info('dygraphs: ' + message);
+ break;
+ case Dygraph.WARNING:
+ console.warn('dygraphs: ' + message);
+ break;
+ case Dygraph.ERROR:
+ console.error('dygraphs: ' + message);
+ break;
+ }
+ }
+};
+
+/** @private */
+Dygraph.info = function(message) {
+ Dygraph.log(Dygraph.INFO, message);
+};
+/** @private */
+Dygraph.prototype.info = Dygraph.info;
+
+/** @private */
+Dygraph.warn = function(message) {
+ Dygraph.log(Dygraph.WARNING, message);
+};
+/** @private */
+Dygraph.prototype.warn = Dygraph.warn;
+
+/** @private */
+Dygraph.error = function(message) {
+ Dygraph.log(Dygraph.ERROR, message);
+};
+/** @private */
+Dygraph.prototype.error = Dygraph.error;
+
+/**
+ * @private
+ * Return the 2d context for a dygraph canvas.
+ *
+ * This method is only exposed for the sake of replacing the function in
+ * automated tests, e.g.
+ *
+ * var oldFunc = Dygraph.getContext();
+ * Dygraph.getContext = function(canvas) {
+ * var realContext = oldFunc(canvas);
+ * return new Proxy(realContext);
+ * };
+ */
+Dygraph.getContext = function(canvas) {
+ return canvas.getContext("2d");
+};
+
+/**
+ * @private
+ * Add an event handler. This smooths a difference between IE and the rest of
+ * the world.
+ * @param { DOM element } el The element to add the event to.
+ * @param { String } evt The name of the event, e.g. 'click' or 'mousemove'.
+ * @param { Function } fn The function to call on the event. The function takes
+ * one parameter: the event object.
+ */
+Dygraph.addEvent = function(el, evt, fn) {
+ var normed_fn = function(e) {
+ if (!e) var e = window.event;
+ fn(e);
+ };
+ if (window.addEventListener) { // Mozilla, Netscape, Firefox
+ el.addEventListener(evt, normed_fn, false);
+ } else { // IE
+ el.attachEvent('on' + evt, normed_fn);
+ }
+};
+
+/**
+ * @private
+ * Cancels further processing of an event. This is useful to prevent default
+ * browser actions, e.g. highlighting text on a double-click.
+ * Based on the article at
+ * http://www.switchonthecode.com/tutorials/javascript-tutorial-the-scroll-wheel
+ * @param { Event } e The event whose normal behavior should be canceled.
+ */
+Dygraph.cancelEvent = function(e) {
+ e = e ? e : window.event;
+ if (e.stopPropagation) {
+ e.stopPropagation();
+ }
+ if (e.preventDefault) {
+ e.preventDefault();
+ }
+ e.cancelBubble = true;
+ e.cancel = true;
+ e.returnValue = false;
+ return false;
+};
+
+/**
+ * Convert hsv values to an rgb(r,g,b) string. Taken from MochiKit.Color. This
+ * is used to generate default series colors which are evenly spaced on the
+ * color wheel.
+ * @param { Number } hue Range is 0.0-1.0.
+ * @param { Number } saturation Range is 0.0-1.0.
+ * @param { Number } value Range is 0.0-1.0.
+ * @return { String } "rgb(r,g,b)" where r, g and b range from 0-255.
+ * @private
+ */
+Dygraph.hsvToRGB = function (hue, saturation, value) {
+ var red;
+ var green;
+ var blue;
+ if (saturation === 0) {
+ red = value;
+ green = value;
+ blue = value;
+ } else {
+ var i = Math.floor(hue * 6);
+ var f = (hue * 6) - i;
+ var p = value * (1 - saturation);
+ var q = value * (1 - (saturation * f));
+ var t = value * (1 - (saturation * (1 - f)));
+ switch (i) {
+ case 1: red = q; green = value; blue = p; break;
+ case 2: red = p; green = value; blue = t; break;
+ case 3: red = p; green = q; blue = value; break;
+ case 4: red = t; green = p; blue = value; break;
+ case 5: red = value; green = p; blue = q; break;
+ case 6: // fall through
+ case 0: red = value; green = t; blue = p; break;
+ }
+ }
+ red = Math.floor(255 * red + 0.5);
+ green = Math.floor(255 * green + 0.5);
+ blue = Math.floor(255 * blue + 0.5);
+ return 'rgb(' + red + ',' + green + ',' + blue + ')';
+};
+
+// The following functions are from quirksmode.org with a modification for Safari from
+// http://blog.firetree.net/2005/07/04/javascript-find-position/
+// http://www.quirksmode.org/js/findpos.html
+
+/** @private */
+Dygraph.findPosX = function(obj) {
+ var curleft = 0;
+ if(obj.offsetParent)
+ while(1)
+ {
+ curleft += obj.offsetLeft;
+ if(!obj.offsetParent)
+ break;
+ obj = obj.offsetParent;
+ }
+ else if(obj.x)
+ curleft += obj.x;
+ return curleft;
+};
+
+/** @private */
+Dygraph.findPosY = function(obj) {
+ var curtop = 0;
+ if(obj.offsetParent)
+ while(1)
+ {
+ curtop += obj.offsetTop;
+ if(!obj.offsetParent)
+ break;
+ obj = obj.offsetParent;
+ }
+ else if(obj.y)
+ curtop += obj.y;
+ return curtop;
+};
+
+/**
+ * @private
+ * Returns the x-coordinate of the event in a coordinate system where the
+ * top-left corner of the page (not the window) is (0,0).
+ * Taken from MochiKit.Signal
+ */
+Dygraph.pageX = function(e) {
+ if (e.pageX) {
+ return (!e.pageX || e.pageX < 0) ? 0 : e.pageX;
+ } else {
+ var de = document;
+ var b = document.body;
+ return e.clientX +
+ (de.scrollLeft || b.scrollLeft) -
+ (de.clientLeft || 0);
+ }
+};
+
+/**
+ * @private
+ * Returns the y-coordinate of the event in a coordinate system where the
+ * top-left corner of the page (not the window) is (0,0).
+ * Taken from MochiKit.Signal
+ */
+Dygraph.pageY = function(e) {
+ if (e.pageY) {
+ return (!e.pageY || e.pageY < 0) ? 0 : e.pageY;
+ } else {
+ var de = document;
+ var b = document.body;
+ return e.clientY +
+ (de.scrollTop || b.scrollTop) -
+ (de.clientTop || 0);
+ }
+};
+
+/**
+ * @private
+ * @param { Number } x The number to consider.
+ * @return { Boolean } Whether the number is zero or NaN.
+ */
+// TODO(danvk): rename this function to something like 'isNonZeroNan'.
+Dygraph.isOK = function(x) {
+ return x && !isNaN(x);
+};
+
+/**
+ * Number formatting function which mimicks the behavior of %g in printf, i.e.
+ * either exponential or fixed format (without trailing 0s) is used depending on
+ * the length of the generated string. The advantage of this format is that
+ * there is a predictable upper bound on the resulting string length,
+ * significant figures are not dropped, and normal numbers are not displayed in
+ * exponential notation.
+ *
+ * NOTE: JavaScript's native toPrecision() is NOT a drop-in replacement for %g.
+ * It creates strings which are too long for absolute values between 10^-4 and
+ * 10^-6, e.g. '0.00001' instead of '1e-5'. See tests/number-format.html for
+ * output examples.
+ *
+ * @param {Number} x The number to format
+ * @param {Number} opt_precision The precision to use, default 2.
+ * @return {String} A string formatted like %g in printf. The max generated
+ * string length should be precision + 6 (e.g 1.123e+300).
+ */
+Dygraph.floatFormat = function(x, opt_precision) {
+ // Avoid invalid precision values; [1, 21] is the valid range.
+ var p = Math.min(Math.max(1, opt_precision || 2), 21);
+
+ // This is deceptively simple. The actual algorithm comes from:
+ //
+ // Max allowed length = p + 4
+ // where 4 comes from 'e+n' and '.'.
+ //
+ // Length of fixed format = 2 + y + p
+ // where 2 comes from '0.' and y = # of leading zeroes.
+ //
+ // Equating the two and solving for y yields y = 2, or 0.00xxxx which is
+ // 1.0e-3.
+ //
+ // Since the behavior of toPrecision() is identical for larger numbers, we
+ // don't have to worry about the other bound.
+ //
+ // Finally, the argument for toExponential() is the number of trailing digits,
+ // so we take off 1 for the value before the '.'.
+ return (Math.abs(x) < 1.0e-3 && x != 0.0) ?
+ x.toExponential(p - 1) : x.toPrecision(p);
+};
+
+/**
+ * @private
+ * Converts '9' to '09' (useful for dates)
+ */
+Dygraph.zeropad = function(x) {
+ if (x < 10) return "0" + x; else return "" + x;
+};
+
+/**
+ * Return a string version of the hours, minutes and seconds portion of a date.
+ * @param {Number} date The JavaScript date (ms since epoch)
+ * @return {String} A time of the form "HH:MM:SS"
+ * @private
+ */
+Dygraph.hmsString_ = function(date) {
+ var zeropad = Dygraph.zeropad;
+ var d = new Date(date);
+ if (d.getSeconds()) {
+ return zeropad(d.getHours()) + ":" +
+ zeropad(d.getMinutes()) + ":" +
+ zeropad(d.getSeconds());
+ } else {
+ return zeropad(d.getHours()) + ":" + zeropad(d.getMinutes());
+ }
+};
+
+/**
+ * Convert a JS date (millis since epoch) to YYYY/MM/DD
+ * @param {Number} date The JavaScript date (ms since epoch)
+ * @return {String} A date of the form "YYYY/MM/DD"
+ * @private
+ */
+Dygraph.dateString_ = function(date) {
+ var zeropad = Dygraph.zeropad;
+ var d = new Date(date);
+
+ // Get the year:
+ var year = "" + d.getFullYear();
+ // Get a 0 padded month string
+ var month = zeropad(d.getMonth() + 1); //months are 0-offset, sigh
+ // Get a 0 padded day string
+ var day = zeropad(d.getDate());
+
+ var ret = "";
+ var frac = d.getHours() * 3600 + d.getMinutes() * 60 + d.getSeconds();
+ if (frac) ret = " " + Dygraph.hmsString_(date);
+
+ return year + "/" + month + "/" + day + ret;
+};
+
+/**
+ * Round a number to the specified number of digits past the decimal point.
+ * @param {Number} num The number to round
+ * @param {Number} places The number of decimals to which to round
+ * @return {Number} The rounded number
+ * @private
+ */
+Dygraph.round_ = function(num, places) {
+ var shift = Math.pow(10, places);
+ return Math.round(num * shift)/shift;
+};
+
+/**
+ * @private
+ * Implementation of binary search over an array.
+ * Currently does not work when val is outside the range of arry's values.
+ * @param { Integer } val the value to search for
+ * @param { Integer[] } arry is the value over which to search
+ * @param { Integer } abs If abs > 0, find the lowest entry greater than val
+ * If abs < 0, find the highest entry less than val.
+ * if abs == 0, find the entry that equals val.
+ * @param { Integer } [low] The first index in arry to consider (optional)
+ * @param { Integer } [high] The last index in arry to consider (optional)
+ */
+Dygraph.binarySearch = function(val, arry, abs, low, high) {
+ if (low == null || high == null) {
+ low = 0;
+ high = arry.length - 1;
+ }
+ if (low > high) {
+ return -1;
+ }
+ if (abs == null) {
+ abs = 0;
+ }
+ var validIndex = function(idx) {
+ return idx >= 0 && idx < arry.length;
+ }
+ var mid = parseInt((low + high) / 2);
+ var element = arry[mid];
+ if (element == val) {
+ return mid;
+ }
+ if (element > val) {
+ if (abs > 0) {
+ // Accept if element > val, but also if prior element < val.
+ var idx = mid - 1;
+ if (validIndex(idx) && arry[idx] < val) {
+ return mid;
+ }
+ }
+ return Dygraph.binarySearch(val, arry, abs, low, mid - 1);
+ }
+ if (element < val) {
+ if (abs < 0) {
+ // Accept if element < val, but also if prior element > val.
+ var idx = mid + 1;
+ if (validIndex(idx) && arry[idx] > val) {
+ return mid;
+ }
+ }
+ return Dygraph.binarySearch(val, arry, abs, mid + 1, high);
+ }
+};
+
+/**
+ * @private
+ * Parses a date, returning the number of milliseconds since epoch. This can be
+ * passed in as an xValueParser in the Dygraph constructor.
+ * TODO(danvk): enumerate formats that this understands.
+ * @param {String} A date in YYYYMMDD format.
+ * @return {Number} Milliseconds since epoch.
+ */
+Dygraph.dateParser = function(dateStr) {
+ var dateStrSlashed;
+ var d;
+ if (dateStr.search("-") != -1) { // e.g. '2009-7-12' or '2009-07-12'
+ dateStrSlashed = dateStr.replace("-", "/", "g");
+ while (dateStrSlashed.search("-") != -1) {
+ dateStrSlashed = dateStrSlashed.replace("-", "/");
+ }
+ d = Dygraph.dateStrToMillis(dateStrSlashed);
+ } else if (dateStr.length == 8) { // e.g. '20090712'
+ // TODO(danvk): remove support for this format. It's confusing.
+ dateStrSlashed = dateStr.substr(0,4) + "/" + dateStr.substr(4,2)
+ + "/" + dateStr.substr(6,2);
+ d = Dygraph.dateStrToMillis(dateStrSlashed);
+ } else {
+ // Any format that Date.parse will accept, e.g. "2009/07/12" or
+ // "2009/07/12 12:34:56"
+ d = Dygraph.dateStrToMillis(dateStr);
+ }
+
+ if (!d || isNaN(d)) {
+ Dygraph.error("Couldn't parse " + dateStr + " as a date");
+ }
+ return d;
+};
+
+/**
+ * @private
+ * This is identical to JavaScript's built-in Date.parse() method, except that
+ * it doesn't get replaced with an incompatible method by aggressive JS
+ * libraries like MooTools or Joomla.
+ * @param { String } str The date string, e.g. "2011/05/06"
+ * @return { Integer } millis since epoch
+ */
+Dygraph.dateStrToMillis = function(str) {
+ return new Date(str).getTime();
+};
+
+// These functions are all based on MochiKit.
+/**
+ * Copies all the properties from o to self.
+ *
+ * @private
+ */
+Dygraph.update = function (self, o) {
+ if (typeof(o) != 'undefined' && o !== null) {
+ for (var k in o) {
+ if (o.hasOwnProperty(k)) {
+ self[k] = o[k];
+ }
+ }
+ }
+ return self;
+};
+
+/**
+ * @private
+ */
+Dygraph.isArrayLike = function (o) {
+ var typ = typeof(o);
+ if (
+ (typ != 'object' && !(typ == 'function' &&
+ typeof(o.item) == 'function')) ||
+ o === null ||
+ typeof(o.length) != 'number' ||
+ o.nodeType === 3
+ ) {
+ return false;
+ }
+ return true;
+};
+
+/**
+ * @private
+ */
+Dygraph.isDateLike = function (o) {
+ if (typeof(o) != "object" || o === null ||
+ typeof(o.getTime) != 'function') {
+ return false;
+ }
+ return true;
+};
+
+/**
+ * @private
+ */
+Dygraph.clone = function(o) {
+ // TODO(danvk): figure out how MochiKit's version works
+ var r = [];
+ for (var i = 0; i < o.length; i++) {
+ if (Dygraph.isArrayLike(o[i])) {
+ r.push(Dygraph.clone(o[i]));
+ } else {
+ r.push(o[i]);
+ }
+ }
+ return r;
+};
+
+/**
+ * @private
+ * Create a new canvas element. This is more complex than a simple
+ * document.createElement("canvas") because of IE and excanvas.
+ */
+Dygraph.createCanvas = function() {
+ var canvas = document.createElement("canvas");
+
+ isIE = (/MSIE/.test(navigator.userAgent) && !window.opera);
+ if (isIE && (typeof(G_vmlCanvasManager) != 'undefined')) {
+ canvas = G_vmlCanvasManager.initElement(canvas);
+ }
+
+ return canvas;
+};
Dygraph.DEFAULT_WIDTH = 480;
Dygraph.DEFAULT_HEIGHT = 320;
-Dygraph.LOG_SCALE = 10;
-Dygraph.LN_TEN = Math.log(Dygraph.LOG_SCALE);
-/** @private */
-Dygraph.log10 = function(x) {
- return Math.log(x) / Dygraph.LN_TEN;
-}
-
// Default attribute values.
Dygraph.DEFAULT_ATTRS = {
highlightCircleSize: 3,
interactionModel: null // will be set to Dygraph.Interaction.defaultModel
};
-// Various logging levels.
-Dygraph.DEBUG = 1;
-Dygraph.INFO = 2;
-Dygraph.WARNING = 3;
-Dygraph.ERROR = 3;
-
// Directions for panning and zooming. Use bit operations when combined
// values are possible.
Dygraph.HORIZONTAL = 1;
// Used for initializing annotation CSS rules only once.
Dygraph.addedAnnotationCSS = false;
-/**
- * @private
- * Return the 2d context for a dygraph canvas.
- *
- * This method is only exposed for the sake of replacing the function in
- * automated tests, e.g.
- *
- * var oldFunc = Dygraph.getContext();
- * Dygraph.getContext = function(canvas) {
- * var realContext = oldFunc(canvas);
- * return new Proxy(realContext);
- * };
- */
-Dygraph.getContext = function(canvas) {
- return canvas.getContext("2d");
-};
-
Dygraph.prototype.__old_init__ = function(div, file, labels, attrs) {
// Labels is no longer a constructor parameter, since it's typically set
// directly from the data source. It also conains a name for the x-axis,
}
};
-// TODO(danvk): any way I can get the line numbers to be this.warn call?
-/**
- * @private
- * Log an error on the JS console at the given severity.
- * @param { Integer } severity One of Dygraph.{DEBUG,INFO,WARNING,ERROR}
- * @param { String } The message to log.
- */
-Dygraph.prototype.log = function(severity, message) {
- if (typeof(console) != 'undefined') {
- switch (severity) {
- case Dygraph.DEBUG:
- console.debug('dygraphs: ' + message);
- break;
- case Dygraph.INFO:
- console.info('dygraphs: ' + message);
- break;
- case Dygraph.WARNING:
- console.warn('dygraphs: ' + message);
- break;
- case Dygraph.ERROR:
- console.error('dygraphs: ' + message);
- break;
- }
- }
-};
-
-/** @private */
-Dygraph.prototype.info = function(message) {
- this.log(Dygraph.INFO, message);
-};
-
-/** @private */
-Dygraph.prototype.warn = function(message) {
- this.log(Dygraph.WARNING, message);
-};
-
-/** @private */
-Dygraph.prototype.error = function(message) {
- this.log(Dygraph.ERROR, message);
-};
-
/**
* Returns the current rolling period, as set by the user or an option.
* @return {Number} The number of points in the rolling window
};
/**
- * @private
- * Add an event handler. This smooths a difference between IE and the rest of
- * the world.
- * @param { DOM element } el The element to add the event to.
- * @param { String } evt The name of the event, e.g. 'click' or 'mousemove'.
- * @param { Function } fn The function to call on the event. The function takes
- * one parameter: the event object.
- */
-Dygraph.addEvent = function(el, evt, fn) {
- var normed_fn = function(e) {
- if (!e) var e = window.event;
- fn(e);
- };
- if (window.addEventListener) { // Mozilla, Netscape, Firefox
- el.addEventListener(evt, normed_fn, false);
- } else { // IE
- el.attachEvent('on' + evt, normed_fn);
- }
-};
-
-
-/**
- * @private
- * Cancels further processing of an event. This is useful to prevent default
- * browser actions, e.g. highlighting text on a double-click.
- * Based on the article at
- * http://www.switchonthecode.com/tutorials/javascript-tutorial-the-scroll-wheel
- * @param { Event } e The event whose normal behavior should be canceled.
- */
-Dygraph.cancelEvent = function(e) {
- e = e ? e : window.event;
- if (e.stopPropagation) {
- e.stopPropagation();
- }
- if (e.preventDefault) {
- e.preventDefault();
- }
- e.cancelBubble = true;
- e.cancel = true;
- e.returnValue = false;
- return false;
-};
-
-
-/**
* Generates interface elements for the Dygraph: a containing div, a div to
* display the current point, and a textbox to adjust the rolling average
* period. Also creates the Renderer/Layout elements.
};
/**
- * Convert hsv values to an rgb(r,g,b) string. Taken from MochiKit.Color. This
- * is used to generate default series colors which are evenly spaced on the
- * color wheel.
- * @param { Number } hue Range is 0.0-1.0.
- * @param { Number } saturation Range is 0.0-1.0.
- * @param { Number } value Range is 0.0-1.0.
- * @return { String } "rgb(r,g,b)" where r, g and b range from 0-255.
- * @private
- */
-Dygraph.hsvToRGB = function (hue, saturation, value) {
- var red;
- var green;
- var blue;
- if (saturation === 0) {
- red = value;
- green = value;
- blue = value;
- } else {
- var i = Math.floor(hue * 6);
- var f = (hue * 6) - i;
- var p = value * (1 - saturation);
- var q = value * (1 - (saturation * f));
- var t = value * (1 - (saturation * (1 - f)));
- switch (i) {
- case 1: red = q; green = value; blue = p; break;
- case 2: red = p; green = value; blue = t; break;
- case 3: red = p; green = q; blue = value; break;
- case 4: red = t; green = p; blue = value; break;
- case 5: red = value; green = p; blue = q; break;
- case 6: // fall through
- case 0: red = value; green = t; blue = p; break;
- }
- }
- red = Math.floor(255 * red + 0.5);
- green = Math.floor(255 * green + 0.5);
- blue = Math.floor(255 * blue + 0.5);
- return 'rgb(' + red + ',' + green + ',' + blue + ')';
-};
-
-
-/**
* Generate a set of distinct colors for the data series. This is done with a
* color wheel. Saturation/Value are customizable, and the hue is
* equally-spaced around the color wheel. If a custom set of colors is
return this.colors_;
};
-// The following functions are from quirksmode.org with a modification for Safari from
-// http://blog.firetree.net/2005/07/04/javascript-find-position/
-// http://www.quirksmode.org/js/findpos.html
-
-/** @private */
-Dygraph.findPosX = function(obj) {
- var curleft = 0;
- if(obj.offsetParent)
- while(1)
- {
- curleft += obj.offsetLeft;
- if(!obj.offsetParent)
- break;
- obj = obj.offsetParent;
- }
- else if(obj.x)
- curleft += obj.x;
- return curleft;
-};
-
-
-/** @private */
-Dygraph.findPosY = function(obj) {
- var curtop = 0;
- if(obj.offsetParent)
- while(1)
- {
- curtop += obj.offsetTop;
- if(!obj.offsetParent)
- break;
- obj = obj.offsetParent;
- }
- else if(obj.y)
- curtop += obj.y;
- return curtop;
-};
-
-
/**
* Create the div that contains information on the selected point(s)
* This goes in the top right of the canvas, unless an external div has already
/**
* @private
- * Returns the x-coordinate of the event in a coordinate system where the
- * top-left corner of the page (not the window) is (0,0).
- * Taken from MochiKit.Signal
- */
-Dygraph.pageX = function(e) {
- if (e.pageX) {
- return (!e.pageX || e.pageX < 0) ? 0 : e.pageX;
- } else {
- var de = document;
- var b = document.body;
- return e.clientX +
- (de.scrollLeft || b.scrollLeft) -
- (de.clientLeft || 0);
- }
-};
-
-/**
- * @private
- * Returns the y-coordinate of the event in a coordinate system where the
- * top-left corner of the page (not the window) is (0,0).
- * Taken from MochiKit.Signal
- */
-Dygraph.pageY = function(e) {
- if (e.pageY) {
- return (!e.pageY || e.pageY < 0) ? 0 : e.pageY;
- } else {
- var de = document;
- var b = document.body;
- return e.clientY +
- (de.scrollTop || b.scrollTop) -
- (de.clientTop || 0);
- }
-};
-
-/**
- * @private
* Converts page the x-coordinate of the event to pixel x-coordinates on the
* canvas (i.e. DOM Coords).
*/
/**
* @private
- * @param { Number } x The number to consider.
- * @return { Boolean } Whether the number is zero or NaN.
- */
-// TODO(danvk): rename this function to something like 'isNonZeroNan'.
-Dygraph.isOK = function(x) {
- return x && !isNaN(x);
-};
-
-/**
- * @private
* Generates HTML for the legend which is displayed when hovering over the
* chart. If no selected points are specified, a default legend is returned
* (this may just be the empty string).
};
/**
- * Number formatting function which mimicks the behavior of %g in printf, i.e.
- * either exponential or fixed format (without trailing 0s) is used depending on
- * the length of the generated string. The advantage of this format is that
- * there is a predictable upper bound on the resulting string length,
- * significant figures are not dropped, and normal numbers are not displayed in
- * exponential notation.
- *
- * NOTE: JavaScript's native toPrecision() is NOT a drop-in replacement for %g.
- * It creates strings which are too long for absolute values between 10^-4 and
- * 10^-6, e.g. '0.00001' instead of '1e-5'. See tests/number-format.html for
- * output examples.
- *
- * @param {Number} x The number to format
- * @param {Number} opt_precision The precision to use, default 2.
- * @return {String} A string formatted like %g in printf. The max generated
- * string length should be precision + 6 (e.g 1.123e+300).
- */
-Dygraph.floatFormat = function(x, opt_precision) {
- // Avoid invalid precision values; [1, 21] is the valid range.
- var p = Math.min(Math.max(1, opt_precision || 2), 21);
-
- // This is deceptively simple. The actual algorithm comes from:
- //
- // Max allowed length = p + 4
- // where 4 comes from 'e+n' and '.'.
- //
- // Length of fixed format = 2 + y + p
- // where 2 comes from '0.' and y = # of leading zeroes.
- //
- // Equating the two and solving for y yields y = 2, or 0.00xxxx which is
- // 1.0e-3.
- //
- // Since the behavior of toPrecision() is identical for larger numbers, we
- // don't have to worry about the other bound.
- //
- // Finally, the argument for toExponential() is the number of trailing digits,
- // so we take off 1 for the value before the '.'.
- return (Math.abs(x) < 1.0e-3 && x != 0.0) ?
- x.toExponential(p - 1) : x.toPrecision(p);
-};
-
-/**
* @private
* Return a string version of a number. This respects the digitsAfterDecimal
* and maxNumberWidth options.
};
/**
- * @private
- * Converts '9' to '09' (useful for dates)
- */
-Dygraph.zeropad = function(x) {
- if (x < 10) return "0" + x; else return "" + x;
-};
-
-/**
- * Return a string version of the hours, minutes and seconds portion of a date.
- * @param {Number} date The JavaScript date (ms since epoch)
- * @return {String} A time of the form "HH:MM:SS"
- * @private
- */
-Dygraph.hmsString_ = function(date) {
- var zeropad = Dygraph.zeropad;
- var d = new Date(date);
- if (d.getSeconds()) {
- return zeropad(d.getHours()) + ":" +
- zeropad(d.getMinutes()) + ":" +
- zeropad(d.getSeconds());
- } else {
- return zeropad(d.getHours()) + ":" + zeropad(d.getMinutes());
- }
-};
-
-/**
* Convert a JS date to a string appropriate to display on an axis that
* is displaying values at the stated granularity.
* @param {Date} date The date to format
};
/**
- * Convert a JS date (millis since epoch) to YYYY/MM/DD
- * @param {Number} date The JavaScript date (ms since epoch)
- * @return {String} A date of the form "YYYY/MM/DD"
- * @private
- */
-Dygraph.dateString_ = function(date) {
- var zeropad = Dygraph.zeropad;
- var d = new Date(date);
-
- // Get the year:
- var year = "" + d.getFullYear();
- // Get a 0 padded month string
- var month = zeropad(d.getMonth() + 1); //months are 0-offset, sigh
- // Get a 0 padded day string
- var day = zeropad(d.getDate());
-
- var ret = "";
- var frac = d.getHours() * 3600 + d.getMinutes() * 60 + d.getSeconds();
- if (frac) ret = " " + Dygraph.hmsString_(date);
-
- return year + "/" + month + "/" + day + ret;
-};
-
-/**
- * Round a number to the specified number of digits past the decimal point.
- * @param {Number} num The number to round
- * @param {Number} places The number of decimals to which to round
- * @return {Number} The rounded number
- * @private
- */
-Dygraph.round_ = function(num, places) {
- var shift = Math.pow(10, places);
- return Math.round(num * shift)/shift;
-};
-
-/**
* Fires when there's data available to be graphed.
* @param {String} data Raw CSV data to be plotted
* @private
return vals;
}();
-/**
- * @private
- * Implementation of binary search over an array.
- * Currently does not work when val is outside the range of arry's values.
- * @param { Integer } val the value to search for
- * @param { Integer[] } arry is the value over which to search
- * @param { Integer } abs If abs > 0, find the lowest entry greater than val
- * If abs < 0, find the highest entry less than val.
- * if abs == 0, find the entry that equals val.
- * @param { Integer } [low] The first index in arry to consider (optional)
- * @param { Integer } [high] The last index in arry to consider (optional)
- */
-Dygraph.binarySearch = function(val, arry, abs, low, high) {
- if (low == null || high == null) {
- low = 0;
- high = arry.length - 1;
- }
- if (low > high) {
- return -1;
- }
- if (abs == null) {
- abs = 0;
- }
- var validIndex = function(idx) {
- return idx >= 0 && idx < arry.length;
- }
- var mid = parseInt((low + high) / 2);
- var element = arry[mid];
- if (element == val) {
- return mid;
- }
- if (element > val) {
- if (abs > 0) {
- // Accept if element > val, but also if prior element < val.
- var idx = mid - 1;
- if (validIndex(idx) && arry[idx] < val) {
- return mid;
- }
- }
- return Dygraph.binarySearch(val, arry, abs, low, mid - 1);
- }
- if (element < val) {
- if (abs < 0) {
- // Accept if element < val, but also if prior element > val.
- var idx = mid + 1;
- if (validIndex(idx) && arry[idx] > val) {
- return mid;
- }
- }
- return Dygraph.binarySearch(val, arry, abs, mid + 1, high);
- }
-};
-
// TODO(konigsberg): Update comment.
/**
* Add ticks when the x axis has numbers on it (instead of dates)
};
/**
- * @private
- * Parses a date, returning the number of milliseconds since epoch. This can be
- * passed in as an xValueParser in the Dygraph constructor.
- * TODO(danvk): enumerate formats that this understands.
- * @param {String} A date in YYYYMMDD format.
- * @return {Number} Milliseconds since epoch.
- */
-Dygraph.dateParser = function(dateStr, self) {
- var dateStrSlashed;
- var d;
- if (dateStr.search("-") != -1) { // e.g. '2009-7-12' or '2009-07-12'
- dateStrSlashed = dateStr.replace("-", "/", "g");
- while (dateStrSlashed.search("-") != -1) {
- dateStrSlashed = dateStrSlashed.replace("-", "/");
- }
- d = Dygraph.dateStrToMillis(dateStrSlashed);
- } else if (dateStr.length == 8) { // e.g. '20090712'
- // TODO(danvk): remove support for this format. It's confusing.
- dateStrSlashed = dateStr.substr(0,4) + "/" + dateStr.substr(4,2)
- + "/" + dateStr.substr(6,2);
- d = Dygraph.dateStrToMillis(dateStrSlashed);
- } else {
- // Any format that Date.parse will accept, e.g. "2009/07/12" or
- // "2009/07/12 12:34:56"
- d = Dygraph.dateStrToMillis(dateStr);
- }
-
- if (!d || isNaN(d)) {
- self.error("Couldn't parse " + dateStr + " as a date");
- }
- return d;
-};
-
-/**
* Detects the type of the str (date or numeric) and sets the various
* formatting attributes in this.attrs_ based on this type.
* @param {String} str An x value.
}
/**
- * @private
- * This is identical to JavaScript's built-in Date.parse() method, except that
- * it doesn't get replaced with an incompatible method by aggressive JS
- * libraries like MooTools or Joomla.
- * @param { String } str The date string, e.g. "2011/05/06"
- * @return { Integer } millis since epoch
- */
-Dygraph.dateStrToMillis = function(str) {
- return new Date(str).getTime();
-};
-
-// These functions are all based on MochiKit.
-/**
- * Copies all the properties from o to self.
- *
- * @private
- */
-Dygraph.update = function (self, o) {
- if (typeof(o) != 'undefined' && o !== null) {
- for (var k in o) {
- if (o.hasOwnProperty(k)) {
- self[k] = o[k];
- }
- }
- }
- return self;
-};
-
-/**
- * @private
- */
-Dygraph.isArrayLike = function (o) {
- var typ = typeof(o);
- if (
- (typ != 'object' && !(typ == 'function' &&
- typeof(o.item) == 'function')) ||
- o === null ||
- typeof(o.length) != 'number' ||
- o.nodeType === 3
- ) {
- return false;
- }
- return true;
-};
-
-/**
- * @private
- */
-Dygraph.isDateLike = function (o) {
- if (typeof(o) != "object" || o === null ||
- typeof(o.getTime) != 'function') {
- return false;
- }
- return true;
-};
-
-/**
- * @private
- */
-Dygraph.clone = function(o) {
- // TODO(danvk): figure out how MochiKit's version works
- var r = [];
- for (var i = 0; i < o.length; i++) {
- if (Dygraph.isArrayLike(o[i])) {
- r.push(Dygraph.clone(o[i]));
- } else {
- r.push(o[i]);
- }
- }
- return r;
-};
-
-
-/**
* Get the CSV data. If it's in a function, call that function. If it's in a
* file, do an XMLHttpRequest to get it.
* @private
this.warn("Unable to add default annotation CSS rule; display may be off.");
}
-/**
- * @private
- * Create a new canvas element. This is more complex than a simple
- * document.createElement("canvas") because of IE and excanvas.
- */
-Dygraph.createCanvas = function() {
- var canvas = document.createElement("canvas");
-
- isIE = (/MSIE/.test(navigator.userAgent) && !window.opera);
- if (isIE && (typeof(G_vmlCanvasManager) != 'undefined')) {
- canvas = G_vmlCanvasManager.initElement(canvas);
- }
-
- return canvas;
-};
-
// Older pages may still use this name.
DateGraph = Dygraph;