update combined
[dygraphs.git] / dygraph.js
index 402bcc7..0ff8bf1 100644 (file)
@@ -91,6 +91,7 @@ Dygraph.DEFAULT_ATTRS = {
   },
   labelsSeparateLines: false,
   labelsKMB: false,
+  labelsKMG2: false,
 
   strokeWidth: 1.0,
 
@@ -193,11 +194,11 @@ Dygraph.prototype.__init__ = function(div, file, attrs) {
 
   // Create the PlotKit grapher
   // TODO(danvk): why does the Layout need its own set of options?
-  this.layoutOptions_ = { 'errorBars': (this.attr_("errorBars") ||
-                                        this.attr_("customBars")),
-                          'xOriginIsZero': false };
+  this.layoutOptions_ = { 'xOriginIsZero': false };
   Dygraph.update(this.layoutOptions_, this.attrs_);
   Dygraph.update(this.layoutOptions_, this.user_attrs_);
+  Dygraph.update(this.layoutOptions_, {
+    'errorBars': (this.attr_("errorBars") || this.attr_("customBars")) });
 
   this.layout_ = new DygraphLayout(this, this.layoutOptions_);
 
@@ -451,7 +452,9 @@ Dygraph.prototype.createStatusMessage_ = function(){
     Dygraph.update(messagestyle, this.attr_('labelsDivStyles'));
     var div = document.createElement("div");
     for (var name in messagestyle) {
-      div.style[name] = messagestyle[name];
+      if (messagestyle.hasOwnProperty(name)) {
+        div.style[name] = messagestyle[name];
+      }
     }
     this.graphDiv.appendChild(div);
     this.attrs_.labelsDiv = div;
@@ -476,7 +479,9 @@ Dygraph.prototype.createRollInterface_ = function() {
   roller.size = "2";
   roller.value = this.rollPeriod_;
   for (var name in textAttr) {
-    roller.style[name] = textAttr[name];
+    if (textAttr.hasOwnProperty(name)) {
+      roller.style[name] = textAttr[name];
+    }
   }
 
   var pa = this.graphDiv;
@@ -1045,17 +1050,30 @@ Dygraph.numericTicks = function(minV, maxV, self) {
 
   // Construct labels for the ticks
   var ticks = [];
+  var k;
+  var k_labels = [];
+  if (self.attr_("labelsKMB")) {
+    k = 1000;
+    k_labels = [ "K", "M", "B", "T" ];
+  }
+  if (self.attr_("labelsKMG2")) {
+    if (k) self.warn("Setting both labelsKMB and labelsKMG2. Pick one!");
+    k = 1024;
+    k_labels = [ "k", "M", "G", "T" ];
+  }
+
   for (var i = 0; i < nTicks; i++) {
     var tickV = low_val + i * scale;
+    var absTickV = Math.abs(tickV);
     var label = self.round_(tickV, 2);
-    if (self.attr_("labelsKMB")) {
-      var k = 1000;
-      if (tickV >= k*k*k) {
-        label = self.round_(tickV/(k*k*k), 1) + "B";
-      } else if (tickV >= k*k) {
-        label = self.round_(tickV/(k*k), 1) + "M";
-      } else if (tickV >= k) {
-        label = self.round_(tickV/k, 1) + "K";
+    if (k_labels.length) {
+      // Round up to an appropriate unit.
+      var n = k*k*k*k;
+      for (var j = 3; j >= 0; j--, n /= k) {
+        if (absTickV >= n) {
+          label = self.round_(tickV / n, 1) + k_labels[j];
+          break;
+        }
       }
     }
     ticks.push( {label: label, v: tickV} );
@@ -1268,16 +1286,20 @@ Dygraph.prototype.rollingAverage = function(originalData, rollPeriod) {
       var y = data[1];
       rollingData[i] = [originalData[i][0], [y, y - data[0], data[2] - y]];
 
-      low += data[0];
-      mid += y;
-      high += data[2];
-      count += 1;
+      if (y != null && !isNaN(y)) {
+        low += data[0];
+        mid += y;
+        high += data[2];
+        count += 1;
+      }
       if (i - rollPeriod >= 0) {
         var prev = originalData[i - rollPeriod];
-        low -= prev[1][0];
-        mid -= prev[1][1];
-        high -= prev[1][2];
-        count -= 1;
+        if (prev[1][1] != null && !isNaN(prev[1][1])) {
+          low -= prev[1][0];
+          mid -= prev[1][1];
+          high -= prev[1][2];
+          count -= 1;
+        }
       }
       rollingData[i] = [originalData[i][0], [ 1.0 * mid / count,
                                               1.0 * (mid - low) / count,
@@ -1297,7 +1319,7 @@ Dygraph.prototype.rollingAverage = function(originalData, rollPeriod) {
         var num_ok = 0;
         for (var j = Math.max(0, i - rollPeriod + 1); j < i + 1; j++) {
           var y = originalData[j][1];
-          if (!y || isNaN(y)) continue;
+          if (y == null || isNaN(y)) continue;
           num_ok++;
           sum += originalData[j][1];
         }
@@ -1315,7 +1337,7 @@ Dygraph.prototype.rollingAverage = function(originalData, rollPeriod) {
         var num_ok = 0;
         for (var j = Math.max(0, i - rollPeriod + 1); j < i + 1; j++) {
           var y = originalData[j][1][0];
-          if (!y || isNaN(y)) continue;
+          if (y == null || isNaN(y)) continue;
           num_ok++;
           sum += originalData[j][1][0];
           variance += Math.pow(originalData[j][1][1], 2);
@@ -1556,8 +1578,10 @@ Dygraph.prototype.parseDataTable_ = function(data) {
   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') {
@@ -1583,8 +1607,14 @@ Dygraph.prototype.parseDataTable_ = function(data) {
     } else {
       row.push(data.getValue(i, 0));
     }
-    for (var j = 1; j < cols; j++) {
-      row.push(data.getValue(i, j));
+    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);
   }
@@ -1595,7 +1625,9 @@ Dygraph.prototype.parseDataTable_ = function(data) {
 Dygraph.update = function (self, o) {
   if (typeof(o) != 'undefined' && o !== null) {
     for (var k in o) {
-      self[k] = o[k];
+      if (o.hasOwnProperty(k)) {
+        self[k] = o[k];
+      }
     }
   }
   return self;