clipping rectangles for interaction layer
[dygraphs.git] / dygraph-canvas.js
index 7ee0039..0aa7ca1 100644 (file)
@@ -4,7 +4,7 @@
 /**
  * @fileoverview Based on PlotKit, but modified to meet the needs of dygraphs.
  * In particular, support for:
- * - grid overlays 
+ * - grid overlays
  * - error bars
  * - dygraphs attribute system
  */
@@ -19,7 +19,7 @@ DygraphLayout = function(dygraph, options) {
   this.options = {};  // TODO(danvk): remove, use attr_ instead.
   Dygraph.update(this.options, options ? options : {});
   this.datasets = new Array();
-  this.annotations = new Array()
+  this.annotations = new Array();
 };
 
 DygraphLayout.prototype.attr_ = function(name) {
@@ -84,8 +84,8 @@ DygraphLayout.prototype._evaluateLimits = function() {
 
   for (var i = 0; i < this.options.yAxes.length; i++) {
     var axis = this.options.yAxes[i];
-    axis.minyval = axis.valueRange[0];
-    axis.maxyval = axis.valueRange[1];
+    axis.minyval = axis.computedValueRange[0];
+    axis.maxyval = axis.computedValueRange[1];
     axis.yrange = axis.maxyval - axis.minyval;
     axis.yscale = (axis.yrange != 0 ? 1.0 / axis.yrange : 1.0);
   }
@@ -111,13 +111,6 @@ DygraphLayout.prototype._evaluateLineCharts = function() {
         name: setName
       };
 
-      // limit the x, y values so they do not overdraw
-      if (point.y <= 0.0) {
-        point.y = 0.0;
-      }
-      if (point.y >= 1.0) {
-        point.y = 1.0;
-      }
       this.points.push(point);
     }
   }
@@ -302,8 +295,33 @@ DygraphCanvasRenderer = function(dygraph, element, layout, options) {
   this.area.h = this.height - this.options.axisLabelFontSize -
                 2 * this.options.axisTickSize;
 
+  // Shrink the drawing area to accomodate additional y-axes.
+  if (this.dygraph_.numAxes() == 2) {
+    // TODO(danvk): per-axis setting.
+    this.area.w -= (this.options.yAxisLabelWidth + 2 * this.options.axisTickSize);
+  } else if (this.dygraph_.numAxes() > 2) {
+    this.dygraph_.error("Only two y-axes are supported at this time. (Trying " +
+                        "to use " + this.dygraph_.numAxes() + ")");
+  }
+
   this.container.style.position = "relative";
   this.container.style.width = this.width + "px";
+
+  // Set up a clipping area for the canvas (and the interaction canvas).
+  // This ensures that we don't overdraw.
+  var ctx = this.dygraph_.canvas_.getContext("2d");
+  ctx.beginPath();
+  ctx.rect(this.area.x, this.area.y, this.area.w, this.area.h);
+  ctx.clip();
+
+  ctx = this.dygraph_.hidden_.getContext("2d");
+  ctx.beginPath();
+  ctx.rect(this.area.x, this.area.y, this.area.w, this.area.h);
+  ctx.clip();
+};
+
+DygraphCanvasRenderer.prototype.attr_ = function(x) {
+  return this.dygraph_.attr_(x);
 };
 
 DygraphCanvasRenderer.prototype.clear = function() {
@@ -368,15 +386,6 @@ DygraphCanvasRenderer.isSupported = function(canvasName) {
  * Draw an X/Y grid on top of the existing plot
  */
 DygraphCanvasRenderer.prototype.render = function() {
-  // Shrink the drawing area to accomodate additional y-axes.
-  if (this.layout.options.yAxes.length == 2) {
-    // TODO(danvk): per-axis setting.
-    this.area.w -= (this.options.yAxisLabelWidth + 2 * this.options.axisTickSize);
-  } else if (this.layout.options.yAxes.length > 2) {
-    this.dygraph_.error("Only two y-axes are supported at this time. (Trying " +
-                        "to use " + this.layout.yAxes.length + ")");
-  }
-
   // Draw the new X/Y grid
   var ctx = this.element.getContext("2d");
 
@@ -390,7 +399,8 @@ DygraphCanvasRenderer.prototype.render = function() {
     ctx.strokeStyle = this.options.gridLineColor;
     ctx.lineWidth = this.options.axisLineWidth;
     for (var i = 0; i < ticks.length; i++) {
-      if (ticks[i][0] != 0) continue;  // TODO(danvk): per-axis property
+      // TODO(danvk): allow secondary axes to draw a grid, too.
+      if (ticks[i][0] != 0) continue;
       var x = this.area.x;
       var y = this.area.y + ticks[i][1] * this.area.h;
       ctx.beginPath();
@@ -407,7 +417,7 @@ DygraphCanvasRenderer.prototype.render = function() {
     ctx.strokeStyle = this.options.gridLineColor;
     ctx.lineWidth = this.options.axisLineWidth;
     for (var i=0; i<ticks.length; i++) {
-      var x = this.area.x + ticks[i][1] * this.area.w;
+      var x = this.area.x + ticks[i][0] * this.area.w;
       var y = this.area.y + this.area.h;
       ctx.beginPath();
       ctx.moveTo(x, y);
@@ -460,13 +470,15 @@ DygraphCanvasRenderer.prototype._renderAxis = function() {
         var tick = this.layout.yticks[i];
         if (typeof(tick) == "function") return;
         var x = this.area.x;
-        if (tick[0] == 1) {
-          x = this.area.x + this.area.w - labelStyle.width;
+        var sgn = 1;
+        if (tick[0] == 1) {  // right-side y-axis
+          x = this.area.x + this.area.w;
+          sgn = -1;
         }
         var y = this.area.y + tick[1] * this.area.h;
         context.beginPath();
         context.moveTo(x, y);
-        context.lineTo(x - this.options.axisTickSize, y);
+        context.lineTo(x - sgn * this.options.axisTickSize, y);
         context.closePath();
         context.stroke();
 
@@ -509,6 +521,14 @@ DygraphCanvasRenderer.prototype._renderAxis = function() {
     context.lineTo(this.area.x, this.area.y + this.area.h);
     context.closePath();
     context.stroke();
+
+    if (this.dygraph_.numAxes() == 2) {
+      context.beginPath();
+      context.moveTo(this.area.x + this.area.w, this.area.y);
+      context.lineTo(this.area.x + this.area.w, this.area.y + this.area.h);
+      context.closePath();
+      context.stroke();
+    }
   }
 
   if (this.options.drawXAxis) {
@@ -659,12 +679,13 @@ DygraphCanvasRenderer.prototype._renderAnnotations = function() {
  * Overrides the CanvasRenderer method to draw error bars
  */
 DygraphCanvasRenderer.prototype._renderLineChart = function() {
+  // TODO(danvk): use this.attr_ for many of these.
   var context = this.element.getContext("2d");
   var colorCount = this.options.colorScheme.length;
   var colorScheme = this.options.colorScheme;
   var fillAlpha = this.options.fillAlpha;
   var errorBars = this.layout.options.errorBars;
-  var fillGraph = this.layout.options.fillGraph;
+  var fillGraph = this.attr_("fillGraph");
   var stackedGraph = this.layout.options.stackedGraph;
   var stepPlot = this.layout.options.stepPlot;