Fix bug 436. Only restore axes that remain after an option update.
[dygraphs.git] / dygraph-canvas.js
index 571191c..e531ece 100644 (file)
@@ -25,7 +25,7 @@
  */
 
 /*jshint globalstrict: true */
-/*global Dygraph:false,RGBColor:false */
+/*global Dygraph:false,RGBColorParser:false */
 "use strict";
 
 
@@ -57,6 +57,8 @@ var DygraphCanvasRenderer = function(dygraph, element, elementContext, layout) {
   this.height = this.element.height;
   this.width = this.element.width;
 
+  this.elementContext.save();
+
   // --- check whether everything is ok before we return
   if (!this.isIE && !(DygraphCanvasRenderer.isSupported(this.element)))
       throw "Canvas is not supported.";
@@ -125,6 +127,11 @@ DygraphCanvasRenderer.prototype.clear = function() {
   context.clearRect(0, 0, this.width, this.height);
 };
 
+DygraphCanvasRenderer.prototype.onDoneDrawing = function() {
+  // balances the save called in the constructor.
+  this.elementContext.restore();
+}
+
 /**
  * Checks whether the browser supports the <canvas> tag.
  * @private
@@ -261,7 +268,8 @@ DygraphCanvasRenderer._drawStyledLine = function(e,
     drawPointCallback, pointSize) {
   var g = e.dygraph;
   // TODO(konigsberg): Compute attributes outside this method call.
-  var stepPlot = g.getOption("stepPlot");  // TODO(danvk): per-series
+  var stepPlot = g.getOption("stepPlot", e.setName);
+
   if (!Dygraph.isArrayLike(strokePattern)) {
     strokePattern = null;
   }
@@ -343,7 +351,7 @@ DygraphCanvasRenderer._drawSeries = function(e,
       isIsolated = false;
       if (drawGapPoints || !prevCanvasX) {
         iter.nextIdx_ = i;
-        var peek = iter.next();
+        iter.next();
         nextCanvasY = iter.hasNext ? iter.peek.canvasy : null;
 
         var isNextCanvasYNullOrNaN = nextCanvasY === null ||
@@ -364,13 +372,12 @@ DygraphCanvasRenderer._drawSeries = function(e,
           if (stepPlot) {
             ctx.moveTo(prevCanvasX, prevCanvasY);
             ctx.lineTo(point.canvasx, prevCanvasY);
-            prevCanvasX = point.canvasx;
           }
 
-          // TODO(danvk): this moveTo is rarely necessary
-          ctx.moveTo(prevCanvasX, prevCanvasY);
           ctx.lineTo(point.canvasx, point.canvasy);
         }
+      } else {
+        ctx.moveTo(point.canvasx, point.canvasy);
       }
       if (drawPoints || isIsolated) {
         pointsOnLine.push([point.canvasx, point.canvasy]);
@@ -445,13 +452,10 @@ DygraphCanvasRenderer.prototype._updatePoints = function() {
  */
 DygraphCanvasRenderer.prototype._renderLineChart = function(opt_seriesName, opt_ctx) {
   var ctx = opt_ctx || this.elementContext;
-  var errorBars = this.attr_("errorBars") || this.attr_("customBars");
-  var fillGraph = this.attr_("fillGraph");
   var i;
 
   var sets = this.layout.points;
   var setNames = this.layout.setNames;
-  var setCount = setNames.length;
   var setName;
 
   this.colors = this.dygraph_.colorsMap_;
@@ -478,7 +482,7 @@ DygraphCanvasRenderer.prototype._renderLineChart = function(opt_seriesName, opt_
 
     for (var j = 0; j < sets.length; j++) {
       setName = setNames[j];
-      if (opt_seriesName && setName != opt_seriesName) continue;
+      if (opt_seriesName && !(is_last && setName == opt_seriesName)) continue;
 
       var points = sets[j];
 
@@ -583,20 +587,19 @@ DygraphCanvasRenderer._linePlotter = function(e) {
  */
 DygraphCanvasRenderer._errorPlotter = function(e) {
   var g = e.dygraph;
+  var setName = e.setName;
   var errorBars = g.getOption("errorBars") || g.getOption("customBars");
   if (!errorBars) return;
 
-  var fillGraph = g.getOption("fillGraph");
+  var fillGraph = g.getOption("fillGraph", setName);
   if (fillGraph) {
     g.warn("Can't use fillGraph option with error bars");
   }
 
-  var setName = e.setName;
   var ctx = e.drawingContext;
   var color = e.color;
   var fillAlpha = g.getOption('fillAlpha', setName);
-  var stepPlot = g.getOption('stepPlot');  // TODO(danvk): per-series
-  var axis = e.axis;
+  var stepPlot = g.getOption("stepPlot", setName);
   var points = e.points;
 
   var iter = Dygraph.createIterator(points, 0, points.length,
@@ -609,16 +612,23 @@ DygraphCanvasRenderer._errorPlotter = function(e) {
   var prevX = NaN;
   var prevY = NaN;
   var prevYs = [-1, -1];
-  var yscale = axis.yscale;
   // should be same color as the lines but only 15% opaque.
-  var rgb = new RGBColor(color);
+  var rgb = new RGBColorParser(color);
   var err_color =
       'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + fillAlpha + ')';
   ctx.fillStyle = err_color;
   ctx.beginPath();
+
+  var isNullUndefinedOrNaN = function(x) {
+    return (x === null ||
+            x === undefined ||
+            isNaN(x));
+  };
+
   while (iter.hasNext) {
     var point = iter.next();
-    if (!Dygraph.isOK(point.y)) {
+    if ((!stepPlot && isNullUndefinedOrNaN(point.y)) ||
+        (stepPlot && !isNaN(prevY) && isNullUndefinedOrNaN(prevY))) {
       prevX = NaN;
       continue;
     }
@@ -633,17 +643,15 @@ DygraphCanvasRenderer._errorPlotter = function(e) {
     newYs[1] = e.plotArea.h * newYs[1] + e.plotArea.y;
     if (!isNaN(prevX)) {
       if (stepPlot) {
-        ctx.moveTo(prevX, newYs[0]);
-      } else {
         ctx.moveTo(prevX, prevYs[0]);
-      }
-      ctx.lineTo(point.canvasx, newYs[0]);
-      ctx.lineTo(point.canvasx, newYs[1]);
-      if (stepPlot) {
-        ctx.lineTo(prevX, newYs[1]);
+        ctx.lineTo(point.canvasx, prevYs[0]);
+        ctx.lineTo(point.canvasx, prevYs[1]);
       } else {
-        ctx.lineTo(prevX, prevYs[1]);
+        ctx.moveTo(prevX, prevYs[0]);
+        ctx.lineTo(point.canvasx, newYs[0]);
+        ctx.lineTo(point.canvasx, newYs[1]);
       }
+      ctx.lineTo(prevX, prevYs[1]);
       ctx.closePath();
     }
     prevYs = newYs;
@@ -663,18 +671,12 @@ DygraphCanvasRenderer._errorPlotter = function(e) {
  * @private
  */
 DygraphCanvasRenderer._fillPlotter = function(e) {
-  var g = e.dygraph;
-  if (!g.getOption("fillGraph")) return;
-
   // We'll handle all the series at once, not one-by-one.
   if (e.seriesIndex !== 0) return;
 
-  var ctx = e.drawingContext;
-  var area = e.plotArea;
-  var sets = e.allSeriesPoints;
-  var setCount = sets.length;
-
+  var g = e.dygraph;
   var setNames = g.getLabels().slice(1);  // remove x-axis
+
   // getLabels() includes names for invisible series, which are not included in
   // allSeriesPoints. We remove those to make the two match.
   // TODO(danvk): provide a simpler way to get this information.
@@ -682,17 +684,34 @@ DygraphCanvasRenderer._fillPlotter = function(e) {
     if (!g.visibility()[i]) setNames.splice(i, 1);
   }
 
+  var anySeriesFilled = (function() {
+    for (var i = 0; i < setNames.length; i++) {
+      if (g.getOption("fillGraph", setNames[i])) return true;
+    }
+    return false;
+  })();
+
+  if (!anySeriesFilled) return;
+
+  var ctx = e.drawingContext;
+  var area = e.plotArea;
+  var sets = e.allSeriesPoints;
+  var setCount = sets.length;
+
   var fillAlpha = g.getOption('fillAlpha');
-  var stepPlot = g.getOption('stepPlot');
   var stackedGraph = g.getOption("stackedGraph");
   var colors = g.getColors();
 
   var baseline = {};  // for stacked graphs: baseline for filling
   var currBaseline;
+  var prevStepPlot;  // for different line drawing modes (line/step) per series
 
   // process sets in reverse order (needed for stacked graphs)
   for (var setIdx = setCount - 1; setIdx >= 0; setIdx--) {
     var setName = setNames[setIdx];
+    if (!g.getOption('fillGraph', setName)) continue;
+    
+    var stepPlot = g.getOption('stepPlot', setName);
     var color = colors[setIdx];
     var axis = g.axisPropertiesForSeries(setName);
     var axisY = 1.0 + axis.minyval * axis.yscale;
@@ -709,9 +728,8 @@ DygraphCanvasRenderer._fillPlotter = function(e) {
     var prevX = NaN;
     var prevYs = [-1, -1];
     var newYs;
-    var yscale = axis.yscale;
     // should be same color as the lines but only 15% opaque.
-    var rgb = new RGBColor(color);
+    var rgb = new RGBColorParser(color);
     var err_color =
         'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + fillAlpha + ')';
     ctx.fillStyle = err_color;
@@ -728,7 +746,7 @@ DygraphCanvasRenderer._fillPlotter = function(e) {
         if (currBaseline === undefined) {
           lastY = axisY;
         } else {
-          if(stepPlot) {
+          if(prevStepPlot) {
             lastY = currBaseline[0];
           } else {
             lastY = currBaseline;
@@ -753,17 +771,18 @@ DygraphCanvasRenderer._fillPlotter = function(e) {
       }
       if (!isNaN(prevX)) {
         ctx.moveTo(prevX, prevYs[0]);
-
+        
+        // Move to top fill point
         if (stepPlot) {
           ctx.lineTo(point.canvasx, prevYs[0]);
-          if(currBaseline) {
-            // Draw to the bottom of the baseline
-            ctx.lineTo(point.canvasx, currBaseline[1]);
-          } else {
-            ctx.lineTo(point.canvasx, newYs[1]);
-          }
         } else {
           ctx.lineTo(point.canvasx, newYs[0]);
+        }
+        // Move to bottom fill point
+        if (prevStepPlot && currBaseline) {
+          // Draw to the bottom of the baseline
+          ctx.lineTo(point.canvasx, currBaseline[1]);
+        } else {
           ctx.lineTo(point.canvasx, newYs[1]);
         }
 
@@ -773,6 +792,7 @@ DygraphCanvasRenderer._fillPlotter = function(e) {
       prevYs = newYs;
       prevX = point.canvasx;
     }
+    prevStepPlot = stepPlot;
     ctx.fill();
   }
 };