Fix connectSeparatedPoints, add test
[dygraphs.git] / dygraph-canvas.js
index 7ae3c87..6e15a58 100644 (file)
@@ -658,8 +658,22 @@ DygraphCanvasRenderer.prototype._renderAnnotations = function() {
   }
 };
 
+DygraphCanvasRenderer.makeNextPointStep_ = function(connect, points, end) {
+  if (connect) {
+    return function(j) {
+      while (++j < end) {
+        if (!(points[j].yval === null)) break;
+      }
+      return j;
+    }
+  } else {
+    return function(j) { return j + 1 };
+  }
+};
+
 DygraphCanvasRenderer.prototype._drawStyledLine = function(
-    ctx, i, color, strokeWidth, strokePattern, drawPoints, pointSize) {
+    ctx, i, setName, color, strokeWidth, strokePattern, drawPoints,
+    drawPointCallback, pointSize) {
   var isNullOrNaN = function(x) {
     return (x === null || isNaN(x));
   };
@@ -671,13 +685,16 @@ DygraphCanvasRenderer.prototype._drawStyledLine = function(
   var points = this.layout.points;
   var prevX = null;
   var prevY = null;
+  var pointsOnLine = []; // Array of [canvasx, canvasy] pairs.
   if (!Dygraph.isArrayLike(strokePattern)) {
     strokePattern = null;
   }
 
   var point;
+  var next = DygraphCanvasRenderer.makeNextPointStep_(
+      this.attr_('connectSeparatedPoints'), points, afterLastIndexInSet);
   ctx.save();
-  for (var j = firstIndexInSet; j < afterLastIndexInSet; j++) {
+  for (var j = firstIndexInSet; j < afterLastIndexInSet; j = next(j)) {
     point = points[j];
     if (isNullOrNaN(point.canvasy)) {
       if (stepPlot && prevX !== null) {
@@ -723,14 +740,17 @@ DygraphCanvasRenderer.prototype._drawStyledLine = function(
       }
 
       if (drawPoints || isIsolated) {
-        ctx.beginPath();
-        ctx.fillStyle = color;
-        ctx.arc(point.canvasx, point.canvasy, pointSize,
-                0, 2 * Math.PI, false);
-        ctx.fill();
+        pointsOnLine.push([point.canvasx, point.canvasy]);
       }
     }
   }
+  for (var idx = 0; idx < pointsOnLine.length; idx++) {
+    var cb = pointsOnLine[idx];
+    ctx.save();
+    drawPointCallback(
+        this.dygraph_, setName, ctx, cb[0], cb[1], color, pointSize);
+    ctx.restore();
+  }
   ctx.restore();
 };
 
@@ -740,20 +760,24 @@ DygraphCanvasRenderer.prototype._drawLine = function(ctx, i) {
 
   var strokeWidth = this.dygraph_.attr_("strokeWidth", setName);
   var borderWidth = this.dygraph_.attr_("strokeBorderWidth", setName);
+  var drawPointCallback = this.dygraph_.attr_("drawPointCallback", setName) ||
+      Dygraph.Circles.DEFAULT;
   if (borderWidth && strokeWidth) {
-    this._drawStyledLine(ctx, i,
+    this._drawStyledLine(ctx, i, setName,
         this.dygraph_.attr_("strokeBorderColor", setName),
         strokeWidth + 2 * borderWidth,
         this.dygraph_.attr_("strokePattern", setName),
         this.dygraph_.attr_("drawPoints", setName),
+        drawPointCallback,
         this.dygraph_.attr_("pointSize", setName));
   }
 
-  this._drawStyledLine(ctx, i,
+  this._drawStyledLine(ctx, i, setName,
       this.colors[setName],
       strokeWidth,
       this.dygraph_.attr_("strokePattern", setName),
       this.dygraph_.attr_("drawPoints", setName),
+      drawPointCallback,
       this.dygraph_.attr_("pointSize", setName));
 };
 
@@ -803,6 +827,14 @@ DygraphCanvasRenderer.prototype._renderLineChart = function() {
       axis = this.dygraph_.axisPropertiesForSeries(setName);
       color = this.colors[setName];
 
+      var firstIndexInSet = this.layout.setPointsOffsets[i];
+      var setLength = this.layout.setPointsLengths[i];
+      var afterLastIndexInSet = firstIndexInSet + setLength;
+
+      var next = DygraphCanvasRenderer.makeNextPointStep_(
+        this.attr_('connectSeparatedPoints'), points,
+        afterLastIndexInSet);
+
       // setup graphics context
       prevX = NaN;
       prevY = NaN;
@@ -814,9 +846,9 @@ DygraphCanvasRenderer.prototype._renderLineChart = function() {
                             fillAlpha + ')';
       ctx.fillStyle = err_color;
       ctx.beginPath();
-      for (j = 0; j < pointsLength; j++) {
+      for (j = firstIndexInSet; j < afterLastIndexInSet; j = next(j)) {
         point = points[j];
-        if (point.name == setName) {
+        if (point.name == setName) { // TODO(klausw): this is always true
           if (!Dygraph.isOK(point.y)) {
             prevX = NaN;
             continue;
@@ -866,6 +898,13 @@ DygraphCanvasRenderer.prototype._renderLineChart = function() {
       if (axisY < 0.0) axisY = 0.0;
       else if (axisY > 1.0) axisY = 1.0;
       axisY = this.area.h * axisY + this.area.y;
+      var firstIndexInSet = this.layout.setPointsOffsets[i];
+      var setLength = this.layout.setPointsLengths[i];
+      var afterLastIndexInSet = firstIndexInSet + setLength;
+
+      var next = DygraphCanvasRenderer.makeNextPointStep_(
+        this.attr_('connectSeparatedPoints'), points,
+        afterLastIndexInSet);
 
       // setup graphics context
       prevX = NaN;
@@ -877,9 +916,9 @@ DygraphCanvasRenderer.prototype._renderLineChart = function() {
                             fillAlpha + ')';
       ctx.fillStyle = err_color;
       ctx.beginPath();
-      for (j = 0; j < pointsLength; j++) {
+      for (j = firstIndexInSet; j < afterLastIndexInSet; j = next(j)) {
         point = points[j];
-        if (point.name == setName) {
+        if (point.name == setName) { // TODO(klausw): this is always true
           if (!Dygraph.isOK(point.y)) {
             prevX = NaN;
             continue;
@@ -913,9 +952,6 @@ DygraphCanvasRenderer.prototype._renderLineChart = function() {
   }
 
   // Drawing the lines.
-  var firstIndexInSet = 0;
-  var afterLastIndexInSet = 0;
-  var setLength = 0;
   for (i = 0; i < setCount; i += 1) {
     this._drawLine(ctx, i);
   }