Some closurifying dygraph-canvas and dygraph-layout.
[dygraphs.git] / dygraph.js
index af1ca65..4316ac3 100644 (file)
@@ -95,6 +95,8 @@ Dygraph.DEFAULT_HEIGHT = 320;
 Dygraph.ANIMATION_STEPS = 12;
 Dygraph.ANIMATION_DURATION = 200;
 
+// Label constants for the labelsKMB and labelsKMG2 options.
+// (i.e. '100000' -> '100K')
 Dygraph.KMB_LABELS = [ 'K', 'M', 'B', 'T', 'Q' ];
 Dygraph.KMG2_BIG_LABELS = [ 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' ];
 Dygraph.KMG2_SMALL_LABELS = [ 'm', 'u', 'n', 'p', 'f', 'a', 'z', 'y' ];
@@ -140,13 +142,13 @@ Dygraph.numberValueFormatter = function(x, opts, pt, g) {
     var m_labels = [];
     if (kmb) {
       k = 1000;
-      k_labels = [ "K", "M", "B", "T", "Q" ];
+      k_labels = Dygraph.KMB_LABELS;
     }
     if (kmg2) {
       if (kmb) Dygraph.warn("Setting both labelsKMB and labelsKMG2. Pick one!");
       k = 1024;
-      k_labels = [ "k", "M", "G", "T", "P", "E", "Z", "Y" ];
-      m_labels = [ "m", "u", "n", "p", "f", "a", "z", "y" ];
+      k_labels = Dygraph.KMG2_BIG_LABELS;
+      m_labels = Dygraph.KMG2_SMALL_LABELS;
     }
 
     var absx = Math.abs(x);
@@ -2333,7 +2335,9 @@ Dygraph.prototype.gatherDatasets_ = function(rolledSeries, dateWindow) {
                      series[j][1][2]];
       }
     } else if (this.attr_("stackedGraph")) {
-      var actual_y, last_x;
+      // Need to clear last_x explicitly as javascript's locals are
+      // local to function, not to a block of statements
+      var actual_y, last_x = null;
       for (j = 0; j < series.length; j++) {
         // If one data set has a NaN, let all subsequent stacked
         // sets inherit the NaN -- only start at 0 for the first set.
@@ -2348,7 +2352,7 @@ Dygraph.prototype.gatherDatasets_ = function(rolledSeries, dateWindow) {
           continue;
         }
 
-        if (j === 0 || last_x != x) {
+        if (last_x != x) {
           cumulative_y[x] += actual_y;
           // If an x-value is repeated, we ignore the duplicates.
         }
@@ -2527,7 +2531,12 @@ Dygraph.prototype.computeYAxes_ = function() {
 
   if (valueWindows !== undefined) {
     // Restore valueWindow settings.
-    for (index = 0; index < valueWindows.length; index++) {
+
+    // When going from two axes back to one, we only restore
+    // one axis.
+    var idxCount = Math.min(valueWindows.length, this.axes_.length);
+
+    for (index = 0; index < idxCount; index++) {
       this.axes_[index].valueWindow = valueWindows[index];
     }
   }
@@ -2587,6 +2596,28 @@ Dygraph.prototype.computeYAxisRanges_ = function(extremes) {
     var includeZero = this.attributes_.getForAxis("includeZero", i);
     series = this.attributes_.seriesForAxis(i);
 
+    // Add some padding. This supports two Y padding operation modes:
+    //
+    // - backwards compatible (yRangePad not set):
+    //   10% padding for automatic Y ranges, but not for user-supplied
+    //   ranges, and move a close-to-zero edge to zero except if
+    //   avoidMinZero is set, since drawing at the edge results in
+    //   invisible lines. Unfortunately lines drawn at the edge of a
+    //   user-supplied range will still be invisible. If logscale is
+    //   set, add a variable amount of padding at the top but
+    //   none at the bottom.
+    //
+    // - new-style (yRangePad set by the user):
+    //   always add the specified Y padding.
+    //
+    ypadCompat = true;
+    ypad = 0.1; // add 10%
+    if (this.attr_('yRangePad') !== null) {
+      ypadCompat = false;
+      // Convert pixel padding to ratio
+      ypad = this.attr_('yRangePad') / this.plotter_.area.h;
+    }
+
     if (series.length === 0) {
       // If no series are defined or visible then use a reasonable default
       axis.extremeRange = [0, 1];
@@ -2633,28 +2664,6 @@ Dygraph.prototype.computeYAxisRanges_ = function(extremes) {
         }
       }
 
-      // Add some padding. This supports two Y padding operation modes:
-      //
-      // - backwards compatible (yRangePad not set):
-      //   10% padding for automatic Y ranges, but not for user-supplied
-      //   ranges, and move a close-to-zero edge to zero except if
-      //   avoidMinZero is set, since drawing at the edge results in
-      //   invisible lines. Unfortunately lines drawn at the edge of a
-      //   user-supplied range will still be invisible. If logscale is
-      //   set, add a variable amount of padding at the top but
-      //   none at the bottom.
-      //
-      // - new-style (yRangePad set by the user):
-      //   always add the specified Y padding.
-      //
-      ypadCompat = true;
-      ypad = 0.1; // add 10%
-      if (this.attr_('yRangePad') !== null) {
-        ypadCompat = false;
-        // Convert pixel padding to ratio
-        ypad = this.attr_('yRangePad') / this.plotter_.area.h;
-      }
-
       var maxAxisY, minAxisY;
       if (logscale) {
         if (ypadCompat) {
@@ -2894,7 +2903,10 @@ Dygraph.prototype.rollingAverage = function(originalData, rollPeriod) {
           rollingData[i] = [originalData[i][0],
                             [sum / num_ok, sigma * stddev, sigma * stddev]];
         } else {
-          rollingData[i] = [originalData[i][0], [null, null, null]];
+          // This explicitly preserves NaNs to aid with "independent series".
+          // See testRollingAveragePreservesNaNs.
+          var v = (rollPeriod == 1) ? originalData[i][1][0] : null;
+          rollingData[i] = [originalData[i][0], [v, v, v]];
         }
       }
     }
@@ -3596,6 +3608,13 @@ Dygraph.prototype.setAnnotations = function(ann, suppressDraw) {
   // Only add the annotation CSS rule once we know it will be used.
   Dygraph.addAnnotationRule();
   this.annotations_ = ann;
+  if (!this.layout_) {
+    this.warn("Tried to setAnnotations before dygraph was ready. " +
+              "Try setting them in a drawCallback. See " +
+              "dygraphs.com/tests/annotation.html");
+    return;
+  }
+
   this.layout_.setAnnotations(this.annotations_);
   if (!suppressDraw) {
     this.predraw_();