X-Git-Url: https://adrianiainlam.tk/git/?a=blobdiff_plain;ds=sidebyside;f=dygraph-utils.js;h=68a31480e6f1207ea44f5d08421ef6b0f334d922;hb=f1ec8cf5aedd62613b954803cb48aaa0a065dc32;hp=086d8f87afd6407375f41a77c96a170c158a62e5;hpb=21ebe38bb1eeae3a7fd73335a411bfd81c66d985;p=dygraphs.git
diff --git a/dygraph-utils.js b/dygraph-utils.js
index 086d8f8..68a3148 100644
--- a/dygraph-utils.js
+++ b/dygraph-utils.js
@@ -33,11 +33,13 @@ Dygraph.INFO = 2;
Dygraph.WARNING = 3;
Dygraph.ERROR = 3;
+//
// Set this to log stack traces on warnings, etc.
// This requires stacktrace.js, which is up to you to provide.
// A copy can be found in the dygraphs repo, or at
// https://github.com/eriwen/javascript-stacktrace
Dygraph.LOG_STACK_TRACES = false;
+//
/** A dotted line stroke pattern. */
Dygraph.DOTTED_LINE = [2, 2];
@@ -53,6 +55,7 @@ Dygraph.DOT_DASH_LINE = [7, 2, 2, 2];
* @private
*/
Dygraph.log = function(severity, message) {
+ //
var st;
if (typeof(printStackTrace) != 'undefined') {
try {
@@ -74,27 +77,40 @@ Dygraph.log = function(severity, message) {
// Oh well, it was worth a shot!
}
}
+ //
if (typeof(window.console) != 'undefined') {
+ // In older versions of Firefox, only console.log is defined.
+ var console = window.console;
+ var log = function(console, method, msg) {
+ if (method && typeof(method) == 'function') {
+ method.call(console, msg);
+ } else {
+ console.log(msg);
+ }
+ };
+
switch (severity) {
case Dygraph.DEBUG:
- window.console.debug('dygraphs: ' + message);
+ log(console, console.debug, 'dygraphs: ' + message);
break;
case Dygraph.INFO:
- window.console.info('dygraphs: ' + message);
+ log(console, console.info, 'dygraphs: ' + message);
break;
case Dygraph.WARNING:
- window.console.warn('dygraphs: ' + message);
+ log(console, console.warn, 'dygraphs: ' + message);
break;
case Dygraph.ERROR:
- window.console.error('dygraphs: ' + message);
+ log(console, console.error, 'dygraphs: ' + message);
break;
}
}
+ //
if (Dygraph.LOG_STACK_TRACES) {
window.console.log(st.join('\n'));
}
+ //
};
/**
@@ -104,11 +120,6 @@ Dygraph.log = function(severity, message) {
Dygraph.info = function(message) {
Dygraph.log(Dygraph.INFO, message);
};
-/**
- * @param {string} message
- * @private
- */
-Dygraph.prototype.info = Dygraph.info;
/**
* @param {string} message
@@ -117,24 +128,13 @@ Dygraph.prototype.info = Dygraph.info;
Dygraph.warn = function(message) {
Dygraph.log(Dygraph.WARNING, message);
};
-/**
- * @param {string} message
- * @private
- */
-Dygraph.prototype.warn = Dygraph.warn;
/**
* @param {string} message
- * @private
*/
Dygraph.error = function(message) {
Dygraph.log(Dygraph.ERROR, message);
};
-/**
- * @param {string} message
- * @private
- */
-Dygraph.prototype.error = Dygraph.error;
/**
* Return the 2d context for a dygraph canvas.
@@ -158,9 +158,9 @@ Dygraph.getContext = function(canvas) {
/**
* Add an event handler. This smooths a difference between IE and the rest of
* the world.
- * @param { !Element } elem The element to add the event to.
- * @param { string } type The type of the event, e.g. 'click' or 'mousemove'.
- * @param { function(Event):(boolean|undefined) } fn The function to call
+ * @param {!Node} elem The element to add the event to.
+ * @param {string} type The type of the event, e.g. 'click' or 'mousemove'.
+ * @param {function(Event):(boolean|undefined)} fn The function to call
* on the event. The function takes one parameter: the event object.
* @private
*/
@@ -177,13 +177,13 @@ Dygraph.addEvent = function addEvent(elem, type, fn) {
* Add an event handler. This event handler is kept until the graph is
* destroyed with a call to graph.destroy().
*
- * @param { !Element } elem The element to add the event to.
- * @param { string } type The type of the event, e.g. 'click' or 'mousemove'.
- * @param { function(Event):(boolean|undefined) } fn The function to call
+ * @param {!Node} elem The element to add the event to.
+ * @param {string} type The type of the event, e.g. 'click' or 'mousemove'.
+ * @param {function(Event):(boolean|undefined)} fn The function to call
* on the event. The function takes one parameter: the event object.
* @private
*/
-Dygraph.prototype.addEvent = function addEvent(elem, type, fn) {
+Dygraph.prototype.addAndTrackEvent = function(elem, type, fn) {
Dygraph.addEvent(elem, type, fn);
this.registeredEvents_.push({ elem : elem, type : type, fn : fn });
};
@@ -191,13 +191,13 @@ Dygraph.prototype.addEvent = function addEvent(elem, type, fn) {
/**
* Remove an event handler. This smooths a difference between IE and the rest
* of the world.
- * @param {!Element} elem The element to add the event to.
+ * @param {!Node} elem The element to remove the event from.
* @param {string} type The type of the event, e.g. 'click' or 'mousemove'.
* @param {function(Event):(boolean|undefined)} fn The function to call
* on the event. The function takes one parameter: the event object.
* @private
*/
-Dygraph.removeEvent = function addEvent(elem, type, fn) {
+Dygraph.removeEvent = function(elem, type, fn) {
if (elem.removeEventListener) {
elem.removeEventListener(type, fn, false);
} else {
@@ -211,12 +211,23 @@ Dygraph.removeEvent = function addEvent(elem, type, fn) {
}
};
+Dygraph.prototype.removeTrackedEvents_ = function() {
+ if (this.registeredEvents_) {
+ for (var idx = 0; idx < this.registeredEvents_.length; idx++) {
+ var reg = this.registeredEvents_[idx];
+ Dygraph.removeEvent(reg.elem, reg.type, reg.fn);
+ }
+ }
+
+ this.registeredEvents_ = [];
+};
+
/**
* 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.
+ * @param {!Event} e The event whose normal behavior should be canceled.
* @private
*/
Dygraph.cancelEvent = function(e) {
@@ -279,64 +290,47 @@ Dygraph.hsvToRGB = function (hue, saturation, value) {
// ... and modifications to support scrolling divs.
/**
- * Find the x-coordinate of the supplied object relative to the left side
- * of the page.
+ * Find the coordinates of an object relative to the top left of the page.
+ *
* TODO(danvk): change obj type from Node -> !Node
* @param {Node} obj
- * @return {number}
+ * @return {{x:number,y:number}}
* @private
*/
-Dygraph.findPosX = function(obj) {
- var curleft = 0;
- if(obj.offsetParent) {
+Dygraph.findPos = function(obj) {
+ var curleft = 0, curtop = 0;
+ if (obj.offsetParent) {
var copyObj = obj;
- while(1) {
- curleft += copyObj.offsetLeft;
- if(!copyObj.offsetParent) {
- break;
+ while (1) {
+ // NOTE: the if statement here is for IE8.
+ var borderLeft = "0", borderTop = "0";
+ if (window.getComputedStyle) {
+ var computedStyle = window.getComputedStyle(copyObj, null);
+ borderLeft = computedStyle.borderLeft || "0";
+ borderTop = computedStyle.borderTop || "0";
}
- copyObj = copyObj.offsetParent;
- }
- } else if(obj.x) {
- curleft += obj.x;
- }
- // This handles the case where the object is inside a scrolled div.
- while(obj && obj != document.body) {
- curleft -= obj.scrollLeft;
- obj = obj.parentNode;
- }
- return curleft;
-};
-
-/**
- * Find the y-coordinate of the supplied object relative to the top of the
- * page.
- * TODO(danvk): change obj type from Node -> !Node
- * TODO(danvk): consolidate with findPosX and return an {x, y} object.
- * @param {Node} obj
- * @return {number}
- * @private
- */
-Dygraph.findPosY = function(obj) {
- var curtop = 0;
- if(obj.offsetParent) {
- var copyObj = obj;
- while(1) {
+ curleft += parseInt(borderLeft, 10) ;
+ curtop += parseInt(borderTop, 10) ;
+ curleft += copyObj.offsetLeft;
curtop += copyObj.offsetTop;
- if(!copyObj.offsetParent) {
+ if (!copyObj.offsetParent) {
break;
}
copyObj = copyObj.offsetParent;
}
- } else if(obj.y) {
- curtop += obj.y;
+ } else {
+ // TODO(danvk): why would obj ever have these properties?
+ if (obj.x) curleft += obj.x;
+ if (obj.y) curtop += obj.y;
}
+
// This handles the case where the object is inside a scrolled div.
- while(obj && obj != document.body) {
+ while (obj && obj != document.body) {
+ curleft -= obj.scrollLeft;
curtop -= obj.scrollTop;
obj = obj.parentNode;
}
- return curtop;
+ return {x: curleft, y: curtop};
};
/**
@@ -380,6 +374,28 @@ Dygraph.pageY = function(e) {
};
/**
+ * Converts page the x-coordinate of the event to pixel x-coordinates on the
+ * canvas (i.e. DOM Coords).
+ * @param {!Event} e Drag event.
+ * @param {!DygraphInteractionContext} context Interaction context object.
+ * @return {number} The amount by which the drag has moved to the right.
+ */
+Dygraph.dragGetX_ = function(e, context) {
+ return Dygraph.pageX(e) - context.px;
+};
+
+/**
+ * Converts page the y-coordinate of the event to pixel y-coordinates on the
+ * canvas (i.e. DOM Coords).
+ * @param {!Event} e Drag event.
+ * @param {!DygraphInteractionContext} context Interaction context object.
+ * @return {number} The amount by which the drag has moved down.
+ */
+Dygraph.dragGetY_ = function(e, context) {
+ return Dygraph.pageY(e) - context.py;
+};
+
+/**
* This returns true unless the parameter is 0, null, undefined or NaN.
* TODO(danvk): rename this function to something like 'isNonZeroNan'.
*
@@ -392,18 +408,18 @@ Dygraph.isOK = function(x) {
};
/**
- * @param { {x:?number,y:?number,yval:?number} } p The point to consider, valid
+ * @param {{x:?number,y:?number,yval:?number}} p The point to consider, valid
* points are {x, y} objects
- * @param { boolean } allowNaNY Treat point with y=NaN as valid
- * @return { boolean } Whether the point has numeric x and y.
+ * @param {boolean=} opt_allowNaNY Treat point with y=NaN as valid
+ * @return {boolean} Whether the point has numeric x and y.
* @private
*/
-Dygraph.isValidPoint = function(p, allowNaNY) {
+Dygraph.isValidPoint = function(p, opt_allowNaNY) {
if (!p) return false; // null or undefined object
if (p.yval === null) return false; // missing point
if (p.x === null || p.x === undefined) return false;
if (p.y === null || p.y === undefined) return false;
- if (isNaN(p.x) || (!allowNaNY && isNaN(p.y))) return false;
+ if (isNaN(p.x) || (!opt_allowNaNY && isNaN(p.y))) return false;
return true;
};
@@ -460,22 +476,90 @@ Dygraph.zeropad = function(x) {
};
/**
+ * Date accessors to get the parts of a calendar date (year, month,
+ * day, hour, minute, second and millisecond) according to local time,
+ * and factory method to call the Date constructor with an array of arguments.
+ */
+Dygraph.DateAccessorsLocal = {
+ getFullYear: function(d) {return d.getFullYear();},
+ getMonth: function(d) {return d.getMonth();},
+ getDate: function(d) {return d.getDate();},
+ getHours: function(d) {return d.getHours();},
+ getMinutes: function(d) {return d.getMinutes();},
+ getSeconds: function(d) {return d.getSeconds();},
+ getMilliseconds: function(d) {return d.getMilliseconds();},
+ getDay: function(d) {return d.getDay();},
+ makeDate: function(y, m, d, hh, mm, ss, ms) {
+ return new Date(y, m, d, hh, mm, ss, ms);
+ }
+};
+
+/**
+ * Date accessors to get the parts of a calendar date (year, month,
+ * day of month, hour, minute, second and millisecond) according to UTC time,
+ * and factory method to call the Date constructor with an array of arguments.
+ */
+Dygraph.DateAccessorsUTC = {
+ getFullYear: function(d) {return d.getUTCFullYear();},
+ getMonth: function(d) {return d.getUTCMonth();},
+ getDate: function(d) {return d.getUTCDate();},
+ getHours: function(d) {return d.getUTCHours();},
+ getMinutes: function(d) {return d.getUTCMinutes();},
+ getSeconds: function(d) {return d.getUTCSeconds();},
+ getMilliseconds: function(d) {return d.getUTCMilliseconds();},
+ getDay: function(d) {return d.getUTCDay();},
+ makeDate: function(y, m, d, hh, mm, ss, ms) {
+ return new Date(Date.UTC(y, m, d, hh, mm, ss, ms));
+ }
+};
+
+/**
* 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"
+ * @param {number} hh The hours (from 0-23)
+ * @param {number} mm The minutes (from 0-59)
+ * @param {number} ss The seconds (from 0-59)
+ * @return {string} A time of the form "HH:MM" or "HH:MM:SS"
* @private
*/
-Dygraph.hmsString_ = function(date) {
+Dygraph.hmsString_ = function(hh, mm, ss) {
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());
+ var ret = zeropad(hh) + ":" + zeropad(mm);
+ if (ss) {
+ ret += ":" + zeropad(ss);
+ }
+ return ret;
+};
+
+/**
+ * Convert a JS date (millis since epoch) to a formatted string.
+ * @param {number} time The JavaScript time value (ms since epoch)
+ * @param {boolean} utc Wether output UTC or local time
+ * @return {string} A date of one of these forms:
+ * "YYYY/MM/DD", "YYYY/MM/DD HH:MM" or "YYYY/MM/DD HH:MM:SS"
+ * @private
+ */
+Dygraph.dateString_ = function(time, utc) {
+ var zeropad = Dygraph.zeropad;
+ var accessors = utc ? Dygraph.DateAccessorsUTC : Dygraph.DateAccessorsLocal;
+ var date = new Date(time);
+ var y = accessors.getFullYear(date);
+ var m = accessors.getMonth(date);
+ var d = accessors.getDate(date);
+ var hh = accessors.getHours(date);
+ var mm = accessors.getMinutes(date);
+ var ss = accessors.getSeconds(date);
+ // Get a year string:
+ var year = "" + y;
+ // Get a 0 padded month string
+ var month = zeropad(m + 1); //months are 0-offset, sigh
+ // Get a 0 padded day string
+ var day = zeropad(d);
+ var frac = hh * 3600 + mm * 60 + ss;
+ var ret = year + "/" + month + "/" + day;
+ if (frac) {
+ ret += " " + Dygraph.hmsString_(hh, mm, ss);
}
+ return ret;
};
/**
@@ -612,7 +696,6 @@ Dygraph.dateStrToMillis = function(str) {
* @param {!Object} self
* @param {!Object} o
* @return {!Object}
- * @private
*/
Dygraph.update = function(self, o) {
if (typeof(o) != 'undefined' && o !== null) {
@@ -667,7 +750,7 @@ Dygraph.updateDeep = function (self, o) {
};
/**
- * @param {Object} o
+ * @param {*} o
* @return {boolean}
* @private
*/
@@ -737,6 +820,37 @@ Dygraph.createCanvas = function() {
};
/**
+ * Returns the context's pixel ratio, which is the ratio between the device
+ * pixel ratio and the backing store ratio. Typically this is 1 for conventional
+ * displays, and > 1 for HiDPI displays (such as the Retina MBP).
+ * See http://www.html5rocks.com/en/tutorials/canvas/hidpi/ for more details.
+ *
+ * @param {!CanvasRenderingContext2D} context The canvas's 2d context.
+ * @return {number} The ratio of the device pixel ratio and the backing store
+ * ratio for the specified context.
+ */
+Dygraph.getContextPixelRatio = function(context) {
+ try {
+ var devicePixelRatio = window.devicePixelRatio;
+ var backingStoreRatio = context.webkitBackingStorePixelRatio ||
+ context.mozBackingStorePixelRatio ||
+ context.msBackingStorePixelRatio ||
+ context.oBackingStorePixelRatio ||
+ context.backingStorePixelRatio;
+ if (devicePixelRatio !== undefined &&
+ backingStorePixelRatio !== undefined) {
+ return devicePixelRatio / backingStoreRatio;
+ } else {
+ // If either value is undefined, the ratio is meaningless so we want to
+ // return 1.
+ return 1;
+ }
+ } catch (e) {
+ return 1;
+ }
+};
+
+/**
* Checks whether the user is on an Android browser.
* Android does not fully support the