+ * The user has provided their data as a pre-packaged JS array. If the x values
+ * are numeric, this is the same as dygraphs' internal format. If the x values
+ * are dates, we need to convert them from Date objects to ms since epoch.
+ * @param {Array.<Object>} data
+ * @return {Array.<Object>} data with numeric x values.
+ */
+Dygraph.prototype.parseArray_ = function(data) {
+ // Peek at the first x value to see if it's numeric.
+ if (data.length == 0) {
+ this.error("Can't plot empty data set");
+ return null;
+ }
+ if (data[0].length == 0) {
+ this.error("Data set cannot contain an empty row");
+ return null;
+ }
+
+ if (this.attr_("labels") == null) {
+ this.warn("Using default labels. Set labels explicitly via 'labels' " +
+ "in the options parameter");
+ this.attrs_.labels = [ "X" ];
+ for (var i = 1; i < data[0].length; i++) {
+ this.attrs_.labels.push("Y" + i);
+ }
+ }
+
+ if (Dygraph.isDateLike(data[0][0])) {
+ // Some intelligent defaults for a date x-axis.
+ this.attrs_.xValueFormatter = Dygraph.dateString_;
+ this.attrs_.xTicker = Dygraph.dateTicker;
+
+ // Assume they're all dates.
+ var parsedData = Dygraph.clone(data);
+ for (var i = 0; i < data.length; i++) {
+ if (parsedData[i].length == 0) {
+ this.error("Row " << (1 + i) << " of data is empty");
+ return null;
+ }
+ if (parsedData[i][0] == null
+ || typeof(parsedData[i][0].getTime) != 'function') {
+ this.error("x value in row " << (1 + i) << " is not a Date");
+ return null;
+ }
+ parsedData[i][0] = parsedData[i][0].getTime();
+ }
+ return parsedData;
+ } else {
+ // Some intelligent defaults for a numeric x-axis.
+ this.attrs_.xValueFormatter = function(x) { return x; };
+ this.attrs_.xTicker = Dygraph.numericTicks;
+ return data;
+ }
+};
+
+/**
+ * Parses a DataTable object from gviz.
+ * The data is expected to have a first column that is either a date or a
+ * number. All subsequent columns must be numbers. If there is a clear mismatch
+ * between this.xValueParser_ and the type of the first column, it will be
+ * fixed. Returned value is in the same format as return value of parseCSV_.
+ * @param {Array.<Object>} data See above.
+ * @private
+ */
+Dygraph.prototype.parseDataTable_ = function(data) {
+ var cols = data.getNumberOfColumns();
+ var rows = data.getNumberOfRows();
+
+ // Read column labels
+ var labels = [];
+ for (var i = 0; i < cols; i++) {
+ labels.push(data.getColumnLabel(i));
+ if (i != 0 && this.attr_("errorBars")) i += 1;
+ }
+ this.attrs_.labels = labels;
+ cols = labels.length;
+
+ var indepType = data.getColumnType(0);
+ if (indepType == 'date') {
+ this.attrs_.xValueFormatter = Dygraph.dateString_;
+ this.attrs_.xValueParser = Dygraph.dateParser;
+ this.attrs_.xTicker = Dygraph.dateTicker;
+ } else if (indepType == 'number') {
+ this.attrs_.xValueFormatter = function(x) { return x; };
+ this.attrs_.xValueParser = function(x) { return parseFloat(x); };
+ this.attrs_.xTicker = Dygraph.numericTicks;
+ } else {
+ this.error("only 'date' and 'number' types are supported for column 1 " +
+ "of DataTable input (Got '" + indepType + "')");
+ return null;
+ }
+
+ var ret = [];
+ for (var i = 0; i < rows; i++) {
+ var row = [];
+ if (!data.getValue(i, 0)) continue;
+ if (indepType == 'date') {
+ row.push(data.getValue(i, 0).getTime());
+ } else {
+ row.push(data.getValue(i, 0));
+ }
+ if (!this.attr_("errorBars")) {
+ for (var j = 1; j < cols; j++) {
+ row.push(data.getValue(i, j));
+ }
+ } else {
+ for (var j = 0; j < cols - 1; j++) {
+ row.push([ data.getValue(i, 1 + 2 * j), data.getValue(i, 2 + 2 * j) ]);
+ }
+ }
+ ret.push(row);
+ }
+ return ret;
+}
+
+// These functions are all based on MochiKit.
+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;
+};
+
+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;
+};
+
+Dygraph.isDateLike = function (o) {
+ if (typeof(o) != "object" || o === null ||
+ typeof(o.getTime) != 'function') {
+ return false;
+ }
+ return true;
+};
+
+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;
+};
+
+
+/**