/**
* 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
*/
* 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
*/
/**
* 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.
* 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) {
};
/**
+ * 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'.
*
};
/**
- * @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;
};
};
/**
- * @param {Object} o
+ * @param {*} o
* @return {boolean}
* @private
*/
};
/**
+ * 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 || 1,
+ backingStoreRatio = context.webkitBackingStorePixelRatio ||
+ context.mozBackingStorePixelRatio ||
+ context.msBackingStorePixelRatio ||
+ context.oBackingStorePixelRatio ||
+ context.backingStorePixelRatio || 1;
+ return devicePixelRatio / backingStoreRatio;
+ } catch (e) {
+ return 1;
+ }
+};
+
+/**
* Checks whether the user is on an Android browser.
* Android does not fully support the <canvas> tag, e.g. w/r/t/ clipping.
* @return {boolean}
var iframes = document.getElementsByTagName("iframe");
for (var i = 0; i < iframes.length; i++) {
var iframe = iframes[i];
- var x = Dygraph.findPosX(iframe),
- y = Dygraph.findPosY(iframe),
+ var pos = Dygraph.findPos(iframe),
+ x = pos.x,
+ y = pos.y,
width = iframe.offsetWidth,
height = iframe.offsetHeight;
div.style.backgroundColor = colorStr;
div.style.visibility = 'hidden';
document.body.appendChild(div);
- var rgbStr = window.getComputedStyle(div).backgroundColor;
+ var rgbStr = window.getComputedStyle(div, null).backgroundColor;
document.body.removeChild(div);
var bits = /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/.exec(rgbStr);
return {
b: parseInt(bits[3], 10)
};
};
+
+/**
+ * Checks whether the browser supports the <canvas> tag.
+ * @param {HTMLCanvasElement=} opt_canvasElement Pass a canvas element as an
+ * optimization if you have one.
+ * @return {boolean} Whether the browser supports canvas.
+ */
+Dygraph.isCanvasSupported = function(opt_canvasElement) {
+ var canvas;
+ try {
+ canvas = opt_canvasElement || document.createElement("canvas");
+ canvas.getContext("2d");
+ }
+ catch (e) {
+ var ie = navigator.appVersion.match(/MSIE (\d\.\d)/);
+ var opera = (navigator.userAgent.toLowerCase().indexOf("opera") != -1);
+ if ((!ie) || (ie[1] < 6) || (opera))
+ return false;
+ return true;
+ }
+ return true;
+};
+
+/**
+ * Parses the value as a floating point number. This is like the parseFloat()
+ * built-in, but with a few differences:
+ * - the empty string is parsed as null, rather than NaN.
+ * - if the string cannot be parsed at all, an error is logged.
+ * If the string can't be parsed, this method returns null.
+ * @param {string} x The string to be parsed
+ * @param {number=} opt_line_no The line number from which the string comes.
+ * @param {string=} opt_line The text of the line from which the string comes.
+ */
+Dygraph.parseFloat_ = function(x, opt_line_no, opt_line) {
+ var val = parseFloat(x);
+ if (!isNaN(val)) return val;
+
+ // Try to figure out what happeend.
+ // If the value is the empty string, parse it as null.
+ if (/^ *$/.test(x)) return null;
+
+ // If it was actually "NaN", return it as NaN.
+ if (/^ *nan *$/i.test(x)) return NaN;
+
+ // Looks like a parsing error.
+ var msg = "Unable to parse '" + x + "' as a number";
+ if (opt_line !== undefined && opt_line_no !== undefined) {
+ msg += " on line " + (1+(opt_line_no||0)) + " ('" + opt_line + "') of CSV.";
+ }
+ Dygraph.error(msg);
+
+ return null;
+};