+
+Dygraph.Circles = {
+ DEFAULT : function(g, name, ctx, canvasx, canvasy, color, radius) {
+ ctx.beginPath();
+ ctx.fillStyle = color;
+ ctx.arc(canvasx, canvasy, radius, 0, 2 * Math.PI, false);
+ ctx.fill();
+ }
+ // For more shapes, include extras/shapes.js
+};
+
+/**
+ * To create a "drag" interaction, you typically register a mousedown event
+ * handler on the element where the drag begins. In that handler, you register a
+ * mouseup handler on the window to determine when the mouse is released,
+ * wherever that release happens. This works well, except when the user releases
+ * the mouse over an off-domain iframe. In that case, the mouseup event is
+ * handled by the iframe and never bubbles up to the window handler.
+ *
+ * To deal with this issue, we cover iframes with high z-index divs to make sure
+ * they don't capture mouseup.
+ *
+ * Usage:
+ * element.addEventListener('mousedown', function() {
+ * var tarper = new Dygraph.IFrameTarp();
+ * tarper.cover();
+ * var mouseUpHandler = function() {
+ * ...
+ * window.removeEventListener(mouseUpHandler);
+ * tarper.uncover();
+ * };
+ * window.addEventListener('mouseup', mouseUpHandler);
+ * };
+ *
+ * @constructor
+ */
+Dygraph.IFrameTarp = function() {
+ /** @type {Array.<!HTMLDivElement>} */
+ this.tarps = [];
+};
+
+/**
+ * Find all the iframes in the document and cover them with high z-index
+ * transparent divs.
+ */
+Dygraph.IFrameTarp.prototype.cover = function() {
+ var iframes = document.getElementsByTagName("iframe");
+ for (var i = 0; i < iframes.length; i++) {
+ var iframe = iframes[i];
+ var pos = Dygraph.findPos(iframe),
+ x = pos.x,
+ y = pos.y,
+ width = iframe.offsetWidth,
+ height = iframe.offsetHeight;
+
+ var div = document.createElement("div");
+ div.style.position = "absolute";
+ div.style.left = x + 'px';
+ div.style.top = y + 'px';
+ div.style.width = width + 'px';
+ div.style.height = height + 'px';
+ div.style.zIndex = 999;
+ document.body.appendChild(div);
+ this.tarps.push(div);
+ }
+};
+
+/**
+ * Remove all the iframe covers. You should call this in a mouseup handler.
+ */
+Dygraph.IFrameTarp.prototype.uncover = function() {
+ for (var i = 0; i < this.tarps.length; i++) {
+ this.tarps[i].parentNode.removeChild(this.tarps[i]);
+ }
+ this.tarps = [];
+};
+
+/**
+ * Determine whether |data| is delimited by CR, CRLF, LF, LFCR.
+ * @param {string} data
+ * @return {?string} the delimiter that was detected (or null on failure).
+ */
+Dygraph.detectLineDelimiter = function(data) {
+ for (var i = 0; i < data.length; i++) {
+ var code = data.charAt(i);
+ if (code === '\r') {
+ // Might actually be "\r\n".
+ if (((i + 1) < data.length) && (data.charAt(i + 1) === '\n')) {
+ return '\r\n';
+ }
+ return code;
+ }
+ if (code === '\n') {
+ // Might actually be "\n\r".
+ if (((i + 1) < data.length) && (data.charAt(i + 1) === '\r')) {
+ return '\n\r';
+ }
+ return code;
+ }
+ }
+
+ return null;
+};
+
+/**
+ * Is one node contained by another?
+ * @param {Node} containee The contained node.
+ * @param {Node} container The container node.
+ * @return {boolean} Whether containee is inside (or equal to) container.
+ * @private
+ */
+Dygraph.isNodeContainedBy = function(containee, container) {
+ if (container === null || containee === null) {
+ return false;
+ }
+ var containeeNode = /** @type {Node} */ (containee);
+ while (containeeNode && containeeNode !== container) {
+ containeeNode = containeeNode.parentNode;
+ }
+ return (containeeNode === container);
+};
+
+
+// This masks some numeric issues in older versions of Firefox,
+// where 1.0/Math.pow(10,2) != Math.pow(10,-2).
+/** @type {function(number,number):number} */
+Dygraph.pow = function(base, exp) {
+ if (exp < 0) {
+ return 1.0 / Math.pow(base, -exp);
+ }
+ return Math.pow(base, exp);
+};
+
+/**
+ * Converts any valid CSS color (hex, rgb(), named color) to an RGB tuple.
+ *
+ * @param {!string} colorStr Any valid CSS color string.
+ * @return {{r:number,g:number,b:number}} Parsed RGB tuple.
+ * @private
+ */
+Dygraph.toRGB_ = function(colorStr) {
+ // TODO(danvk): cache color parses to avoid repeated DOM manipulation.
+ var div = document.createElement('div');
+ div.style.backgroundColor = colorStr;
+ div.style.visibility = 'hidden';
+ document.body.appendChild(div);
+ 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 {
+ r: parseInt(bits[1], 10),
+ g: parseInt(bits[2], 10),
+ 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) {
+ try {
+ var canvas = opt_canvasElement || document.createElement("canvas");
+ canvas.getContext("2d");
+ } catch (e) {
+ return false;
+ }
+ 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.";
+ }
+ console.error(msg);
+
+ return null;
+};
+
+})();