push tags when doing a release
[dygraphs.git] / dygraph.js
index 8764430..f05ac47 100644 (file)
@@ -44,7 +44,7 @@
  */
 
 /*jshint globalstrict: true */
-/*global DygraphLayout:false, DygraphCanvasRenderer:false, DygraphOptions:false, G_vmlCanvasManager:false */
+/*global DygraphLayout:false, DygraphCanvasRenderer:false, DygraphOptions:false, G_vmlCanvasManager:false,ActiveXObject:false */
 "use strict";
 
 /**
  * options, see http://dygraphs.com/options.html.
  */
 var Dygraph = function(div, data, opts, opt_fourth_param) {
+  // These have to go above the "Hack for IE" in __init__ since .ready() can be
+  // called as soon as the constructor returns. Once support for OldIE is
+  // dropped, this can go down with the rest of the initializers.
+  this.is_initial_draw_ = true;
+  this.readyFns_ = [];
+
   if (opt_fourth_param !== undefined) {
     // 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
@@ -74,7 +80,7 @@ var Dygraph = function(div, data, opts, opt_fourth_param) {
 };
 
 Dygraph.NAME = "Dygraph";
-Dygraph.VERSION = "1.2";
+Dygraph.VERSION = "1.0.0";
 Dygraph.__repr__ = function() {
   return "[" + this.NAME + " " + this.VERSION + "]";
 };
@@ -439,7 +445,6 @@ Dygraph.prototype.__init__ = function(div, file, attrs) {
   this.fractions_ = attrs.fractions || false;
   this.dateWindow_ = attrs.dateWindow || null;
 
-  this.is_initial_draw_ = true;
   this.annotations_ = [];
 
   // Zoomed indicators - These indicate when the graph has been zoomed and on what axis.
@@ -1412,7 +1417,7 @@ Dygraph.prototype.drawZoomRect_ = function(direction, startX, endX, startY,
   if (prevDirection == Dygraph.HORIZONTAL) {
     ctx.clearRect(Math.min(startX, prevEndX), this.layout_.getPlotArea().y,
                   Math.abs(startX - prevEndX), this.layout_.getPlotArea().h);
-  } else if (prevDirection == Dygraph.VERTICAL){
+  } else if (prevDirection == Dygraph.VERTICAL) {
     ctx.clearRect(this.layout_.getPlotArea().x, Math.min(startY, prevEndY),
                   this.layout_.getPlotArea().w, Math.abs(startY - prevEndY));
   }
@@ -1697,7 +1702,7 @@ Dygraph.prototype.eventToDomCoords = function(event) {
  */
 Dygraph.prototype.findClosestRow = function(domX) {
   var minDistX = Infinity;
-  var pointIdx = -1, setIdx = -1;
+  var closestRow = -1;
   var sets = this.layout_.points;
   for (var i = 0; i < sets.length; i++) {
     var points = sets[i];
@@ -1708,14 +1713,12 @@ Dygraph.prototype.findClosestRow = function(domX) {
       var dist = Math.abs(point.canvasx - domX);
       if (dist < minDistX) {
         minDistX = dist;
-        setIdx = i;
-        pointIdx = j;
+        closestRow = point.idx;
       }
     }
   }
 
-  // TODO(danvk): remove this function; it's trivial and has only one use.
-  return this.idxToRow_(setIdx, pointIdx);
+  return closestRow;
 };
 
 /**
@@ -1862,8 +1865,8 @@ Dygraph.prototype.mouseMove_ = function(event) {
  * @private
  */
 Dygraph.prototype.getLeftBoundary_ = function(setIdx) {
-  if(!isNaN(setIdx) && setIdx < this.boundaryIds_.length){
-    return this.boundaryIds_[setIdx][0];
+  if (this.boundaryIds_[setIdx]) {
+      return this.boundaryIds_[setIdx][0];
   } else {
     for (var i = 0; i < this.boundaryIds_.length; i++) {
       if (this.boundaryIds_[i] !== undefined) {
@@ -1874,19 +1877,6 @@ Dygraph.prototype.getLeftBoundary_ = function(setIdx) {
   }
 };
 
-/**
- * Transforms layout_.points index into data row number.
- * @param int layout_.points index
- * @return int row number, or -1 if none could be found.
- * @private
- */
-Dygraph.prototype.idxToRow_ = function(setIdx, rowIdx) {
-  if (rowIdx < 0) return -1;
-
-  var boundary = this.getLeftBoundary_(setIdx);
-  return boundary + rowIdx;
-};
-
 Dygraph.prototype.animateSelection_ = function(direction) {
   var totalSteps = 10;
   var millis = 30;
@@ -2227,7 +2217,7 @@ Dygraph.prototype.predraw_ = function() {
     this.plotter_.clear();
   }
 
-  if(!this.is_initial_draw_) {
+  if (!this.is_initial_draw_) {
     this.canvas_ctx_.restore();
     this.hidden_ctx_.restore();
   }
@@ -2297,6 +2287,7 @@ Dygraph.PointType = undefined;
 /**
  * Converts a series to a Point array.
  *
+ * @private
  * @param {Array.<Array.<(?number|Array<?number>)>} series Array where
  *     series[row] = [x,y] or [x, [y, err]] or [x, [y, yplus, yminus]].
  * @param {boolean} bars True if error bars or custom bars are being drawn.
@@ -2348,6 +2339,7 @@ Dygraph.seriesToPoints_ = function(series, bars, setName, boundaryIdStart) {
  *     to reflect the stacked values.
  * @param {string} fillMethod Interpolation method, one of 'all', 'inside', or
  *     'none'.
+ * @private
  */
 Dygraph.stackPoints_ = function(
     points, cumulativeYval, seriesExtremes, fillMethod) {
@@ -2625,6 +2617,13 @@ Dygraph.prototype.renderGraph_ = function(is_initial_draw) {
   if (this.attr_("drawCallback") !== null) {
     this.attr_("drawCallback")(this, is_initial_draw);
   }
+  if (is_initial_draw) {
+    this.readyFired_ = true;
+    while (this.readyFns_.length > 0) {
+      var fn = this.readyFns_.pop();
+      fn(this);
+    }
+  }
 };
 
 /**
@@ -2855,7 +2854,7 @@ Dygraph.prototype.computeYAxisRanges_ = function(extremes) {
     }
     
     
-    if(independentTicks) {
+    if (independentTicks) {
       axis.independentTicks = independentTicks;
       var opts = this.optionsViewForAxis_('y' + (i ? '2' : ''));
       var ticker = opts('ticker');
@@ -3042,7 +3041,7 @@ Dygraph.prototype.rollingAverage = function(originalData, rollPeriod) {
   } else {
     // Calculate the rolling average for the first rollPeriod - 1 points where
     // there is not enough data to roll over the full number of points
-    if (!this.attr_("errorBars")){
+    if (!this.attr_("errorBars")) {
       if (rollPeriod == 1) {
         return originalData;
       }
@@ -3547,7 +3546,16 @@ Dygraph.prototype.start_ = function() {
     if (line_delimiter) {
       this.loadedEvent_(data);
     } else {
-      var req = new XMLHttpRequest();
+      // REMOVE_FOR_IE
+      var req;
+      if (window.XMLHttpRequest) {
+        // Firefox, Opera, IE7, and other browsers will use the native object
+        req = new XMLHttpRequest();
+      } else {
+        // IE 5 and 6 will use the ActiveX control
+        req = new ActiveXObject("Microsoft.XMLHTTP");
+      }
+
       var caller = this;
       req.onreadystatechange = function () {
         if (req.readyState == 4) {
@@ -3780,7 +3788,7 @@ Dygraph.prototype.setAnnotations = function(ann, suppressDraw) {
   this.annotations_ = ann;
   if (!this.layout_) {
     this.warn("Tried to setAnnotations before dygraph was ready. " +
-              "Try setting them in a drawCallback. See " +
+              "Try setting them in a ready() block. See " +
               "dygraphs.com/tests/annotation.html");
     return;
   }
@@ -3818,12 +3826,23 @@ Dygraph.prototype.indexFromSetName = function(name) {
 };
 
 /**
- * Get the internal dataset index given its name. These are numbered starting from 0,
- * and only count visible sets.
- * @private
+ * Trigger a callback when the dygraph has drawn itself and is ready to be
+ * manipulated. This is primarily useful when dygraphs has to do an XHR for the
+ * data (i.e. a URL is passed as the data source) and the chart is drawn
+ * asynchronously. If the chart has already drawn, the callback will fire
+ * immediately.
+ *
+ * This is a good place to call setAnnotation().
+ *
+ * @param {function(!Dygraph)} callback The callback to trigger when the chart
+ *     is ready.
  */
-Dygraph.prototype.datasetIndexFromSetName_ = function(name) {
-  return this.datasetIndex_[this.indexFromSetName(name)];
+Dygraph.prototype.ready = function(callback) {
+  if (this.is_initial_draw_) {
+    this.readyFns_.push(callback);
+  } else {
+    callback(this);
+  }
 };
 
 /**