Merge pull request #292 from joanpau
authorDan Vanderkam <danvdk@gmail.com>
Wed, 5 Nov 2014 14:40:38 +0000 (09:40 -0500)
committerDan Vanderkam <danvdk@gmail.com>
Wed, 5 Nov 2014 14:40:38 +0000 (09:40 -0500)
Conflicts:
dygraph-tickers.js

1  2 
dygraph-options-reference.js
dygraph-utils.js
dygraph.js

@@@ -486,6 -486,12 +486,12 @@@ Dygraph.OPTIONS_REFERENCE =  // <JSON
      "type": "boolean",
      "description": "When set, display the graph as a step plot instead of a line plot. This option may either be set for the whole graph or for single series."
    },
+   "labelsUTC": {
+     "default": "false",
+     "labels": ["Value display/formatting", "Axis display"],
+     "type": "boolean",
+     "description": "Show date/time labels according to UTC (instead of local time)."
+   },
    "labelsKMB": {
      "default": "false",
      "labels": ["Value display/formatting"],
      "type": "string",
      "description": "The range selector mini plot fill color. This can be of the form \"#AABBCC\" or \"rgb(255,100,200)\" or \"yellow\". You can also specify null or \"\" to turn off fill."
    },
 +  "showInRangeSelector": {
 +    "default": "null",
 +    "labels": ["Interactive Elements"],
 +    "type": "boolean",
 +    "description": "Mark this series for inclusion in the range selector. The mini plot curve will be an average of all such series. If this is not specified for any series, the default behavior is to average all the series. Setting it for one series will result in that series being charted alone in the range selector."
 +  },
    "animatedZooms": {
      "default": "false",
      "labels": ["Interactive Elements"],
diff --combined dygraph-utils.js
@@@ -12,7 -12,7 +12,7 @@@
   */
  
  /*jshint globalstrict: true */
 -/*global Dygraph:false, G_vmlCanvasManager:false, Node:false, printStackTrace: false */
 +/*global Dygraph:false, G_vmlCanvasManager:false, Node:false */
  "use strict";
  
  Dygraph.LOG_SCALE = 10;
@@@ -27,6 -27,20 +27,6 @@@ 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;
 -
 -// <REMOVE_FOR_COMBINED>
 -// 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;
 -// </REMOVE_FOR_COMBINED>
 -
  /** A dotted line stroke pattern. */
  Dygraph.DOTTED_LINE = [2, 2];
  /** A dashed line stroke pattern. */
@@@ -35,6 -49,94 +35,6 @@@ Dygraph.DASHED_LINE = [7, 3]
  Dygraph.DOT_DASH_LINE = [7, 2, 2, 2];
  
  /**
 - * Log an error on the JS console at the given severity.
 - * @param {number} severity One of Dygraph.{DEBUG,INFO,WARNING,ERROR}
 - * @param {string} message The message to log.
 - * @private
 - */
 -Dygraph.log = function(severity, message) {
 -  // <REMOVE_FOR_COMBINED>
 -  var st;
 -  if (typeof(printStackTrace) != 'undefined') {
 -    try {
 -      // Remove uninteresting bits: logging functions and paths.
 -      st = printStackTrace({guess:false});
 -      while (st[0].indexOf("stacktrace") != -1) {
 -        st.splice(0, 1);
 -      }
 -
 -      st.splice(0, 2);
 -      for (var i = 0; i < st.length; i++) {
 -        st[i] = st[i].replace(/\([^)]*\/(.*)\)/, '@$1')
 -            .replace(/\@.*\/([^\/]*)/, '@$1')
 -            .replace('[object Object].', '');
 -      }
 -      var top_msg = st.splice(0, 1)[0];
 -      message += ' (' + top_msg.replace(/^.*@ ?/, '') + ')';
 -    } catch(e) {
 -      // Oh well, it was worth a shot!
 -    }
 -  }
 -  // </REMOVE_FOR_COMBINED>
 -
 -  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:
 -        log(console, console.debug, 'dygraphs: ' + message);
 -        break;
 -      case Dygraph.INFO:
 -        log(console, console.info, 'dygraphs: ' + message);
 -        break;
 -      case Dygraph.WARNING:
 -        log(console, console.warn, 'dygraphs: ' + message);
 -        break;
 -      case Dygraph.ERROR:
 -        log(console, console.error, 'dygraphs: ' + message);
 -        break;
 -    }
 -  }
 -
 -  // <REMOVE_FOR_COMBINED>
 -  if (Dygraph.LOG_STACK_TRACES) {
 -    window.console.log(st.join('\n'));
 -  }
 -  // </REMOVE_FOR_COMBINED>
 -};
 -
 -/**
 - * @param {string} message
 - * @private
 - */
 -Dygraph.info = function(message) {
 -  Dygraph.log(Dygraph.INFO, message);
 -};
 -
 -/**
 - * @param {string} message
 - * @private
 - */
 -Dygraph.warn = function(message) {
 -  Dygraph.log(Dygraph.WARNING, message);
 -};
 -
 -/**
 - * @param {string} message
 - */
 -Dygraph.error = function(message) {
 -  Dygraph.log(Dygraph.ERROR, message);
 -};
 -
 -/**
   * Return the 2d context for a dygraph canvas.
   *
   * This method is only exposed for the sake of replacing the function in
@@@ -374,46 -476,90 +374,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 YYYY/MM/DD
-  * @param {number} date The JavaScript date (ms since epoch)
-  * @return {string} A date of the form "YYYY/MM/DD"
+  * 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(date) {
+ Dygraph.dateString_ = function(time, utc) {
    var zeropad = Dygraph.zeropad;
-   var d = new Date(date);
-   // Get the year:
-   var year = "" + d.getFullYear();
+   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(d.getMonth() + 1);  //months are 0-offset, sigh
+   var month = zeropad(m + 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;
+   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;
  };
  
  /**
@@@ -526,7 -672,7 +570,7 @@@ Dygraph.dateParser = function(dateStr) 
    }
  
    if (!d || isNaN(d)) {
 -    Dygraph.error("Couldn't parse " + dateStr + " as a date");
 +    console.error("Couldn't parse " + dateStr + " as a date");
    }
    return d;
  };
@@@ -1088,37 -1234,6 +1132,6 @@@ Dygraph.pow = function(base, exp) 
    return Math.pow(base, exp);
  };
  
- // For Dygraph.setDateSameTZ, below.
- Dygraph.dateSetters = {
-   ms: Date.prototype.setMilliseconds,
-   s: Date.prototype.setSeconds,
-   m: Date.prototype.setMinutes,
-   h: Date.prototype.setHours
- };
- /**
-  * This is like calling d.setSeconds(), d.setMinutes(), etc, except that it
-  * adjusts for time zone changes to keep the date/time parts consistent.
-  *
-  * For example, d.getSeconds(), d.getMinutes() and d.getHours() will all be
-  * the same before/after you call setDateSameTZ(d, {ms: 0}). The same is not
-  * true if you call d.setMilliseconds(0).
-  *
-  * @type {function(!Date, Object.<number>)}
-  */
- Dygraph.setDateSameTZ = function(d, parts) {
-   var tz = d.getTimezoneOffset();
-   for (var k in parts) {
-     if (!parts.hasOwnProperty(k)) continue;
-     var setter = Dygraph.dateSetters[k];
-     if (!setter) throw "Invalid setter: " + k;
-     setter.call(d, parts[k]);
-     if (d.getTimezoneOffset() != tz) {
-       d.setTime(d.getTime() + (tz - d.getTimezoneOffset()) * 60 * 1000);
-     }
-   }
- };
  /**
   * Converts any valid CSS color (hex, rgb(), named color) to an RGB tuple.
   *
@@@ -1190,7 -1305,7 +1203,7 @@@ Dygraph.parseFloat_ = function(x, opt_l
    if (opt_line !== undefined && opt_line_no !== undefined) {
      msg += " on line " + (1+(opt_line_no||0)) + " ('" + opt_line + "') of CSV.";
    }
 -  Dygraph.error(msg);
 +  console.error(msg);
  
    return null;
  };
diff --combined dygraph.js
@@@ -72,7 -72,7 +72,7 @@@ var Dygraph = function(div, data, opts
      // Old versions of dygraphs took in the series labels as a constructor
      // parameter. This doesn't make sense anymore, but it's easy to continue
      // to support this usage.
 -    Dygraph.warn("Using deprecated four-argument dygraph constructor");
 +    console.warn("Using deprecated four-argument dygraph constructor");
      this.__old_init__(div, data, opts, opt_fourth_param);
    } else {
      this.__init__(div, data, opts);
@@@ -151,7 -151,7 +151,7 @@@ Dygraph.numberValueFormatter = function
        k_labels = Dygraph.KMB_LABELS;
      }
      if (kmg2) {
 -      if (kmb) Dygraph.warn("Setting both labelsKMB and labelsKMG2. Pick one!");
 +      if (kmb) console.warn("Setting both labelsKMB and labelsKMG2. Pick one!");
        k = 1024;
        k_labels = Dygraph.KMG2_BIG_LABELS;
        m_labels = Dygraph.KMG2_SMALL_LABELS;
@@@ -202,28 -202,53 +202,53 @@@ Dygraph.SHORT_MONTH_NAMES_ = ['Jan', 'F
  
  /**
   * Convert a JS date to a string appropriate to display on an axis that
-  * is displaying values at the stated granularity.
+  * is displaying values at the stated granularity. This respects the 
+  * labelsUTC option.
   * @param {Date} date The date to format
   * @param {number} granularity One of the Dygraph granularity constants
-  * @return {string} The formatted date
+  * @param {Dygraph} opts An options view
+  * @return {string} The date formatted as local time
   * @private
   */
- Dygraph.dateAxisFormatter = function(date, granularity) {
+ Dygraph.dateAxisLabelFormatter = function(date, granularity, opts) {
+   var utc = opts('labelsUTC');
+   var accessors = utc ? Dygraph.DateAccessorsUTC : Dygraph.DateAccessorsLocal;
+   var year = accessors.getFullYear(date),
+       month = accessors.getMonth(date),
+       day = accessors.getDate(date),
+       hours = accessors.getHours(date),
+       mins = accessors.getMinutes(date),
+       secs = accessors.getSeconds(date),
+       millis = accessors.getSeconds(date);
    if (granularity >= Dygraph.DECADAL) {
-     return '' + date.getFullYear();
+     return '' + year;
    } else if (granularity >= Dygraph.MONTHLY) {
-     return Dygraph.SHORT_MONTH_NAMES_[date.getMonth()] + ' ' + date.getFullYear();
+     return Dygraph.SHORT_MONTH_NAMES_[month] + ' ' + year;
    } else {
-     var frac = date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds() + date.getMilliseconds();
+     var frac = hours * 3600 + mins * 60 + secs + 1e-3 * millis;
      if (frac === 0 || granularity >= Dygraph.DAILY) {
        // e.g. '21Jan' (%d%b)
-       var nd = new Date(date.getTime() + 3600*1000);
-       return Dygraph.zeropad(nd.getDate()) + Dygraph.SHORT_MONTH_NAMES_[nd.getMonth()];
+       return Dygraph.zeropad(day) + Dygraph.SHORT_MONTH_NAMES_[month];
      } else {
-       return Dygraph.hmsString_(date.getTime());
+       return Dygraph.hmsString_(hours, mins, secs);
      }
    }
  };
+ // alias in case anyone is referencing the old method.
+ Dygraph.dateAxisFormatter = Dygraph.dateAxisLabelFormatter;
+ /**
+  * Return a string version of a JS date for a value label. This respects the 
+  * labelsUTC option.
+  * @param {Date} date The date to be formatted
+  * @param {Dygraph} opts An options view
+  * @private
+  */
+ Dygraph.dateValueFormatter = function(d, opts) {
+   return Dygraph.dateString_(d, opts('labelsUTC'));
+ };
  
  /**
   * Standard plotters. These may be used by clients.
@@@ -320,7 -345,6 +345,7 @@@ Dygraph.DEFAULT_ATTRS = 
    rangeSelectorHeight: 40,
    rangeSelectorPlotStrokeColor: "#808FAB",
    rangeSelectorPlotFillColor: "#A7B1C4",
 +  showInRangeSelector: null,
  
    // The ordering here ensures that central lines always appear above any
    // fill bars/error bars.
    axes: {
      x: {
        pixelsPerLabel: 60,
-       axisLabelFormatter: Dygraph.dateAxisFormatter,
-       valueFormatter: Dygraph.dateString_,
+       axisLabelFormatter: Dygraph.dateAxisLabelFormatter,
+       valueFormatter: Dygraph.dateValueFormatter,
        drawGrid: true,
        drawAxis: true,
        independentTicks: true,
@@@ -420,7 -444,7 +445,7 @@@ Dygraph.prototype.__init__ = function(d
    }
  
    if (!div) {
 -    Dygraph.error("Constructing dygraph with a non-existent div!");
 +    console.error("Constructing dygraph with a non-existent div!");
      return;
    }
  
@@@ -642,9 -666,9 +667,9 @@@ Dygraph.prototype.toString = function(
  Dygraph.prototype.attr_ = function(name, seriesName) {
  // <REMOVE_FOR_COMBINED>
    if (typeof(Dygraph.OPTIONS_REFERENCE) === 'undefined') {
 -    Dygraph.error('Must include options reference JS for testing');
 +    console.error('Must include options reference JS for testing');
    } else if (!Dygraph.OPTIONS_REFERENCE.hasOwnProperty(name)) {
 -    Dygraph.error('Dygraphs is using property ' + name + ', which has no ' +
 +    console.error('Dygraphs is using property ' + name + ', which has no ' +
                    'entry in the Dygraphs.OPTIONS_REFERENCE listing.');
      // Only log this error once.
      Dygraph.OPTIONS_REFERENCE[name] = true;
@@@ -2649,7 -2673,7 +2674,7 @@@ Dygraph.prototype.drawGraph_ = function
  
    if (this.getStringOption("timingName")) {
      var end = new Date();
 -    Dygraph.info(this.getStringOption("timingName") + " - drawGraph: " + (end - start) + "ms");
 +    console.log(this.getStringOption("timingName") + " - drawGraph: " + (end - start) + "ms");
    }
  };
  
@@@ -2993,9 -3017,9 +3018,9 @@@ Dygraph.prototype.detectTypeFromString
  Dygraph.prototype.setXAxisOptions_ = function(isDate) {
    if (isDate) {
      this.attrs_.xValueParser = Dygraph.dateParser;
-     this.attrs_.axes.x.valueFormatter = Dygraph.dateString_;
+     this.attrs_.axes.x.valueFormatter = Dygraph.dateValueFormatter;
      this.attrs_.axes.x.ticker = Dygraph.dateTicker;
-     this.attrs_.axes.x.axisLabelFormatter = Dygraph.dateAxisFormatter;
+     this.attrs_.axes.x.axisLabelFormatter = Dygraph.dateAxisLabelFormatter;
    } else {
      /** @private (shut up, jsdoc!) */
      this.attrs_.xValueParser = function(x) { return parseFloat(x); };
@@@ -3071,7 -3095,7 +3096,7 @@@ Dygraph.prototype.parseCSV_ = function(
          // TODO(danvk): figure out an appropriate way to flag parse errors.
          vals = inFields[j].split("/");
          if (vals.length != 2) {
 -          Dygraph.error('Expected fractional "num/den" values in CSV data ' +
 +          console.error('Expected fractional "num/den" values in CSV data ' +
                          "but found a value '" + inFields[j] + "' on line " +
                          (1 + i) + " ('" + line + "') which is not of this form.");
            fields[j] = [0, 0];
      } else if (this.getBooleanOption("errorBars")) {
        // If there are error bars, values are (value, stddev) pairs
        if (inFields.length % 2 != 1) {
 -        Dygraph.error('Expected alternating (value, stdev.) pairs in CSV data ' +
 +        console.error('Expected alternating (value, stdev.) pairs in CSV data ' +
                        'but line ' + (1 + i) + ' has an odd number of values (' +
                        (inFields.length - 1) + "): '" + line + "'");
        }
                            Dygraph.parseFloat_(vals[1], i, line),
                            Dygraph.parseFloat_(vals[2], i, line) ];
            } else {
 -            Dygraph.warn('When using customBars, values must be either blank ' +
 +            console.warn('When using customBars, values must be either blank ' +
                           'or "low;center;high" tuples (got "' + val +
                           '" on line ' + (1+i));
            }
      }
  
      if (fields.length != expectedCols) {
 -      Dygraph.error("Number of columns in line " + i + " (" + fields.length +
 +      console.error("Number of columns in line " + i + " (" + fields.length +
                      ") does not agree with number of labels (" + expectedCols +
                      ") " + line);
      }
          if (fields[j]) all_null = false;
        }
        if (all_null) {
 -        Dygraph.warn("The dygraphs 'labels' option is set, but the first row " +
 +        console.warn("The dygraphs 'labels' option is set, but the first row " +
                       "of CSV data ('" + line + "') appears to also contain " +
                       "labels. Will drop the CSV labels and use the option " +
                       "labels.");
    }
  
    if (outOfOrder) {
 -    Dygraph.warn("CSV is out of order; order it correctly to speed loading.");
 +    console.warn("CSV is out of order; order it correctly to speed loading.");
      ret.sort(function(a,b) { return a[0] - b[0]; });
    }
  
  Dygraph.prototype.parseArray_ = function(data) {
    // Peek at the first x value to see if it's numeric.
    if (data.length === 0) {
 -    Dygraph.error("Can't plot empty data set");
 +    console.error("Can't plot empty data set");
      return null;
    }
    if (data[0].length === 0) {
 -    Dygraph.error("Data set cannot contain an empty row");
 +    console.error("Data set cannot contain an empty row");
      return null;
    }
  
    var i;
    if (this.attr_("labels") === null) {
 -    Dygraph.warn("Using default labels. Set labels explicitly via 'labels' " +
 +    console.warn("Using default labels. Set labels explicitly via 'labels' " +
                   "in the options parameter");
      this.attrs_.labels = [ "X" ];
      for (i = 1; i < data[0].length; i++) {
    } else {
      var num_labels = this.attr_("labels");
      if (num_labels.length != data[0].length) {
 -      Dygraph.error("Mismatch between number of labels (" + num_labels + ")" +
 +      console.error("Mismatch between number of labels (" + num_labels + ")" +
                      " and number of columns in array (" + data[0].length + ")");
        return null;
      }
  
    if (Dygraph.isDateLike(data[0][0])) {
      // Some intelligent defaults for a date x-axis.
-     this.attrs_.axes.x.valueFormatter = Dygraph.dateString_;
+     this.attrs_.axes.x.valueFormatter = Dygraph.dateValueFormatter;
      this.attrs_.axes.x.ticker = Dygraph.dateTicker;
-     this.attrs_.axes.x.axisLabelFormatter = Dygraph.dateAxisFormatter;
+     this.attrs_.axes.x.axisLabelFormatter = Dygraph.dateAxisLabelFormatter;
  
      // Assume they're all dates.
      var parsedData = Dygraph.clone(data);
      for (i = 0; i < data.length; i++) {
        if (parsedData[i].length === 0) {
 -        Dygraph.error("Row " + (1 + i) + " of data is empty");
 +        console.error("Row " + (1 + i) + " of data is empty");
          return null;
        }
        if (parsedData[i][0] === null ||
            typeof(parsedData[i][0].getTime) != 'function' ||
            isNaN(parsedData[i][0].getTime())) {
 -        Dygraph.error("x value in row " + (1 + i) + " is not a Date");
 +        console.error("x value in row " + (1 + i) + " is not a Date");
          return null;
        }
        parsedData[i][0] = parsedData[i][0].getTime();
@@@ -3252,16 -3276,16 +3277,16 @@@ Dygraph.prototype.parseDataTable_ = fun
    var indepType = data.getColumnType(0);
    if (indepType == 'date' || indepType == 'datetime') {
      this.attrs_.xValueParser = Dygraph.dateParser;
-     this.attrs_.axes.x.valueFormatter = Dygraph.dateString_;
+     this.attrs_.axes.x.valueFormatter = Dygraph.dateValueFormatter;
      this.attrs_.axes.x.ticker = Dygraph.dateTicker;
-     this.attrs_.axes.x.axisLabelFormatter = Dygraph.dateAxisFormatter;
+     this.attrs_.axes.x.axisLabelFormatter = Dygraph.dateAxisLabelFormatter;
    } else if (indepType == 'number') {
      this.attrs_.xValueParser = function(x) { return parseFloat(x); };
      this.attrs_.axes.x.valueFormatter = function(x) { return x; };
      this.attrs_.axes.x.ticker = Dygraph.numericTicks;
      this.attrs_.axes.x.axisLabelFormatter = this.attrs_.axes.x.valueFormatter;
    } else {
 -    Dygraph.error("only 'date', 'datetime' and 'number' types are supported " +
 +    console.error("only 'date', 'datetime' and 'number' types are supported " +
                    "for column 1 of DataTable input (Got '" + indepType + "')");
      return null;
    }
        }
        hasAnnotations = true;
      } else {
 -      Dygraph.error("Only 'number' is supported as a dependent type with Gviz." +
 +      console.error("Only 'number' is supported as a dependent type with Gviz." +
                      " 'string' is only supported if displayAnnotations is true");
      }
    }
      var row = [];
      if (typeof(data.getValue(i, 0)) === 'undefined' ||
          data.getValue(i, 0) === null) {
 -      Dygraph.warn("Ignoring row " + i +
 +      console.warn("Ignoring row " + i +
                     " of DataTable because of undefined or null first column.");
        continue;
      }
    }
  
    if (outOfOrder) {
 -    Dygraph.warn("DataTable is out of order; order it correctly to speed loading.");
 +    console.warn("DataTable is out of order; order it correctly to speed loading.");
      ret.sort(function(a,b) { return a[0] - b[0]; });
    }
    this.rawData_ = ret;
@@@ -3415,7 -3439,7 +3440,7 @@@ Dygraph.prototype.start_ = function() 
        req.send(null);
      }
    } else {
 -    Dygraph.error("Unknown data format: " + (typeof data));
 +    console.error("Unknown data format: " + (typeof data));
    }
  };
  
@@@ -3506,7 -3530,7 +3531,7 @@@ Dygraph.mapLegacyOptions_ = function(at
    };
    var map = function(opt, axis, new_opt) {
      if (typeof(attrs[opt]) != 'undefined') {
 -      Dygraph.warn("Option " + opt + " is deprecated. Use the " +
 +      console.warn("Option " + opt + " is deprecated. Use the " +
            new_opt + " option for the " + axis + " axis instead. " +
            "(e.g. { axes : { " + axis + " : { " + new_opt + " : ... } } } " +
            "(see http://dygraphs.com/per-axis.html for more information.");
@@@ -3549,7 -3573,7 +3574,7 @@@ Dygraph.prototype.resize = function(wid
    this.resize_lock = true;
  
    if ((width === null) != (height === null)) {
 -    Dygraph.warn("Dygraph.resize() should be called with zero parameters or " +
 +    console.warn("Dygraph.resize() should be called with zero parameters or " +
                   "two non-NULL parameters. Pretending it was zero.");
      width = height = null;
    }
@@@ -3612,7 -3636,7 +3637,7 @@@ Dygraph.prototype.visibility = function
  Dygraph.prototype.setVisibility = function(num, value) {
    var x = this.visibility();
    if (num < 0 || num >= x.length) {
 -    Dygraph.warn("invalid series number in setVisibility: " + num);
 +    console.warn("invalid series number in setVisibility: " + num);
    } else {
      x[num] = value;
      this.predraw_();
@@@ -3640,7 -3664,7 +3665,7 @@@ Dygraph.prototype.setAnnotations = func
    Dygraph.addAnnotationRule();
    this.annotations_ = ann;
    if (!this.layout_) {
 -    Dygraph.warn("Tried to setAnnotations before dygraph was ready. " +
 +    console.warn("Tried to setAnnotations before dygraph was ready. " +
                   "Try setting them in a ready() block. See " +
                   "dygraphs.com/tests/annotation.html");
      return;
@@@ -3737,5 -3761,5 +3762,5 @@@ Dygraph.addAnnotationRule = function() 
      }
    }
  
 -  Dygraph.warn("Unable to add default annotation CSS rule; display may be off.");
 +  console.warn("Unable to add default annotation CSS rule; display may be off.");
  };