Merge branch 'master' of github.com:danvk/dygraphs
[dygraphs.git] / dygraph.js
index af2e821..d89056e 100644 (file)
@@ -304,9 +304,6 @@ Dygraph.prototype.__init__ = function(div, file, attrs) {
 
   this.boundaryIds_ = [];
 
-  // Make a note of whether labels will be pulled from the CSV file.
-  this.labelsFromCSV_ = (this.attr_("labels") == null);
-
   // Create the containing DIV and other interactive elements
   this.createInterface_();
 
@@ -559,7 +556,7 @@ Dygraph.prototype.toDataYCoord = function(y, axis) {
 
   if (typeof(axis) == "undefined") axis = 0;
   if (!this.axes_[axis].logscale) {
-    return yRange[0] + (area.h - y) / area.h * (yRange[1] - yRange[0]);
+    return yRange[0] + (area.y + area.h - y) / area.h * (yRange[1] - yRange[0]);
   } else {
     // Computing the inverse of toDomCoord.
     var pct = (y - area.y) / area.h
@@ -1681,6 +1678,9 @@ Dygraph.prototype.doUnzoom_ = function() {
     }
   }
 
+  // Clear any selection, since it's likely to be drawn in the wrong place.
+  this.clearSelection();
+
   if (dirty) {
     // Putting the drawing operation before the callback because it resets
     // yAxisRange.
@@ -2807,8 +2807,10 @@ Dygraph.prototype.drawGraph_ = function() {
     this.setLegendHTML_();
   } else {
     if (typeof(this.selPoints_) !== 'undefined' && this.selPoints_.length) {
-      this.lastx_ = this.selPoints_[0].xval;
-      this.updateSelection_();
+      // We should select the point nearest the page x/y here, but it's easier
+      // to just clear the selection. This prevents erroneous hover dots from
+      // being displayed.
+      this.clearSelection();
     } else {
       this.clearSelection();
     }
@@ -3315,9 +3317,10 @@ Dygraph.prototype.parseCSV_ = function(data) {
   }
 
   var start = 0;
-  if (this.labelsFromCSV_) {
+  if (!('labels' in this.user_attrs_)) {
+    // User hasn't explicitly set labels, so they're (presumably) in the CSV.
     start = 1;
-    this.attrs_.labels = lines[0].split(delim);
+    this.attrs_.labels = lines[0].split(delim);  // NOTE: _not_ user_attrs_.
   }
   var line_no = 0;
 
@@ -3712,7 +3715,8 @@ Dygraph.prototype.start_ = function() {
       var caller = this;
       req.onreadystatechange = function () {
         if (req.readyState == 4) {
-          if (req.status == 200) {
+          if (req.status == 200 ||  // Normal http
+              req.status == 0) {    // Chrome w/ --allow-file-access-from-files
             caller.loadedEvent_(req.responseText);
           }
         }
@@ -3733,10 +3737,20 @@ Dygraph.prototype.start_ = function() {
  * <li>errorBars: changes whether the data contains stddev</li>
  * </ul>
  *
+ * There's a huge variety of options that can be passed to this method. For a
+ * full list, see http://dygraphs.com/options.html.
+ *
  * @param {Object} attrs The new properties and values
+ * @param {Boolean} [block_redraw] Usually the chart is redrawn after every
+ * call to updateOptions(). If you know better, you can pass true to explicitly
+ * block the redraw. This can be useful for chaining updateOptions() calls,
+ * avoiding the occasional infinite loop and preventing redraws when it's not
+ * necessary (e.g. when updating a callback).
  */
-Dygraph.prototype.updateOptions = function(attrs) {
-  // TODO(danvk): this is a mess. Rethink this function.
+Dygraph.prototype.updateOptions = function(attrs, block_redraw) {
+  if (typeof(block_redraw) == 'undefined') block_redraw = false;
+
+  // TODO(danvk): this is a mess. Move these options into attr_.
   if ('rollPeriod' in attrs) {
     this.rollPeriod_ = attrs.rollPeriod;
   }
@@ -3759,13 +3773,11 @@ Dygraph.prototype.updateOptions = function(attrs) {
 
   Dygraph.update(this.user_attrs_, attrs);
 
-  this.labelsFromCSV_ = (this.attr_("labels") == null);
-
   if (attrs['file']) {
     this.file_ = attrs['file'];
-    this.start_();
+    if (!block_redraw) this.start_();
   } else {
-    this.predraw_();
+    if (!block_redraw) this.predraw_();
   }
 };
 
@@ -4188,6 +4200,12 @@ Dygraph.OPTIONS_REFERENCE =  // <JSON>
     "type": "integer",
     "description": "Width, in pixels, of the x-axis labels."
   },
+  "xAxisHeight": {
+    "default": "(null)",
+    "labels": ["Axis display"],
+    "type": "integer",
+    "description": "Height, in pixels, of the x-axis. If not set explicitly, this is computed based on axisLabelFontSize and axisTickSize."
+  },
   "showLabelsOnHighlight": {
     "default": "true",
     "labels": ["Interactive Elements", "Legend"],
@@ -4405,7 +4423,7 @@ Dygraph.OPTIONS_REFERENCE =  // <JSON>
   },
   "panEdgeFraction": {
     "default": "null",
-    "labels": ["Axis Display", "Interactive Elements"],
+    "labels": ["Axis display", "Interactive Elements"],
     "type": "float",
     "default": "null",
     "description": "A value representing the farthest a graph may be panned, in percent of the display. For example, a value of 0.1 means that the graph can only be panned 10% pased the edges of the displayed values. null means no bounds."
@@ -4496,7 +4514,7 @@ Dygraph.OPTIONS_REFERENCE =  // <JSON>
   },
   "fillAlpha": {
     "default": "0.15",
-    "labels": ["Error bars"],
+    "labels": ["Error Bars", "Data Series Colors"],
     "type": "float (0.0 - 1.0)",
     "description" : "Error bars (or custom bars) for each series are drawn in the same color as the series, but with partial transparency. This sets the transparency. A value of 0.0 means that the error bars will not be drawn, whereas a value of 1.0 means that the error bars will be as dark as the line for the series itself. This can be used to produce chart lines whose thickness varies at each point."
   },
@@ -4529,6 +4547,12 @@ Dygraph.OPTIONS_REFERENCE =  // <JSON>
     "labels": ["Value display/formatting"],
     "type": "integer",
     "description": "When displaying numbers in normal (not scientific) mode, large numbers will be displayed with many trailing zeros (e.g. 100000000 instead of 1e9). This can lead to unwieldy y-axis labels. If there are more than <code>maxNumberWidth</code> digits to the left of the decimal in a number, dygraphs will switch to scientific notation, even when not operating in scientific mode. If you'd like to see all those digits, set this to something large, like 20 or 30."
+  },
+  "file": {
+    "default": "(set when constructed)",
+    "labels": ["Data"],
+    "type": "string (URL of CSV or CSV), GViz DataTable or 2D Array",
+    "description": "Sets the data being displayed in the chart. This can only be set when calling updateOptions; it cannot be set from the constructor. For a full description of valid data formats, see the <a href='http://dygraphs.com/data.html'>Data Formats</a> page."
   }
 }
 ;  // </JSON>
@@ -4547,6 +4571,7 @@ Dygraph.OPTIONS_REFERENCE =  // <JSON>
    'Chart labels',
    'CSV parsing',
    'Callbacks',
+   'Data',
    'Data Line display',
    'Data Series Colors',
    'Error Bars',
@@ -4574,6 +4599,7 @@ Dygraph.OPTIONS_REFERENCE =  // <JSON>
     var labels = op['labels'];
     if (typeof(labels) !== 'object') {
       warn('Option "' + k + '" is missing a "labels": [...] option');
+    } else {
       for (var i = 0; i < labels.length; i++) {
         if (!cats.hasOwnProperty(labels[i])) {
           warn('Option "' + k + '" has label "' + labels[i] +