merge upstream changes
[dygraphs.git] / dygraph-canvas.js
index c5eb835..04280c4 100644 (file)
@@ -2,32 +2,22 @@
 // All Rights Reserved.
 
 /**
- * @fileoverview Based on PlotKit, but modified to meet the needs of dygraphs.
+ * @fileoverview Based on PlotKit.CanvasRenderer, but modified to meet the
+ * needs of dygraphs.
+ *
  * In particular, support for:
  * - grid overlays
  * - error bars
  * - dygraphs attribute system
- *
- * High level overview of classes:
- *
- * - DygraphLayout
- *     This contains all the data to be charted.
- *     It uses data coordinates, but also records the chart range (in data
- *     coordinates) and hence is able to calculate percentage positions ('In
- *     this view, Point A lies 25% down the x-axis.')
- *     Two things that it does not do are:
- *     1. Record pixel coordinates for anything.
- *     2. (oddly) determine anything about the layout of chart elements.
- *     The naming is a vestige of Dygraph's original PlotKit roots.
- *
- * - DygraphCanvasRenderer
- *     This class determines the charting area (in pixel coordinates), maps the
- *     percentage coordinates in the DygraphLayout to pixels and draws them.
- *     It's also responsible for creating chart DOM elements, i.e. annotations,
- *     tick mark labels, the title and the x/y-axis labels.
  */
 
 /**
+ * This class determines the charting area (in pixel coordinates), maps the
+ * percentage coordinates in the DygraphLayout to pixels and draws them.
+ * It's also responsible for creating chart DOM elements, i.e. annotations,
+ * tick mark labels, the title and the x/y-axis labels.
+ * This class is based on PlotKit.CanvasRenderer.
+ *
  * Creates a new DygraphLayout object.
  * @return {Object} The DygraphLayout object
  */
@@ -70,7 +60,7 @@ DygraphLayout.prototype.setAnnotations = function(ann) {
       return;
     }
     Dygraph.update(a, ann[i]);
-    if (!a.xval) a.xval = parse(a.x);
+    if (!a.xval) a.xval = parse(a.x, this.dygraph_);
     this.annotations.push(a);
   }
 };
@@ -281,10 +271,12 @@ DygraphLayout.prototype.unstackPointAtIndex = function(idx) {
 /**
  * The DygraphCanvasRenderer class does the actual rendering of the chart onto
  * a canvas. It's based on PlotKit.CanvasRenderer.
+>>>>>>> master
  * @param {Object} element The canvas to attach to
  * @param {Object} elementContext The 2d context of the canvas (injected so it
  * can be mocked for testing.)
  * @param {Layout} layout The DygraphLayout object for this graph.
+ * @constructor
  */
 DygraphCanvasRenderer = function(dygraph, element, elementContext, layout) {
   this.dygraph_ = dygraph;
@@ -344,7 +336,11 @@ DygraphCanvasRenderer.prototype.computeArea_ = function() {
   area.w = this.width - area.x - this.attr_('rightGap');
   area.h = this.height;
   if (this.attr_('drawXAxis')) {
-    area.h -= this.attr_('axisLabelFontSize') + 2 * this.attr_('axisTickSize');
+    if (this.attr_('xAxisHeight')) {
+      area.h -= this.attr_('xAxisHeight');
+    } else {
+      area.h -= this.attr_('axisLabelFontSize') + 2 * this.attr_('axisTickSize');
+    }
   }
 
   // Shrink the drawing area to accomodate additional y-axes.
@@ -519,16 +515,21 @@ DygraphCanvasRenderer.prototype._renderAxis = function() {
     zIndex: 10,
     color: this.attr_('axisLabelColor'),
     width: this.attr_('axisLabelWidth') + "px",
+    // height: this.attr_('axisLabelFontSize') + 2 + "px",
     overflow: "hidden"
   };
-  var makeDiv = function(txt) {
+  var makeDiv = function(txt, axis) {
     var div = document.createElement("div");
     for (var name in labelStyle) {
       if (labelStyle.hasOwnProperty(name)) {
         div.style[name] = labelStyle[name];
       }
     }
-    div.appendChild(document.createTextNode(txt));
+    var inner_div = document.createElement("div");
+    // TODO(danvk): separate class for secondary y-axis
+    inner_div.className = 'dygraph-axis-label dygraph-axis-label-' + axis;
+    inner_div.appendChild(document.createTextNode(txt));
+    div.appendChild(inner_div);
     return div;
   };
 
@@ -555,7 +556,7 @@ DygraphCanvasRenderer.prototype._renderAxis = function() {
         context.closePath();
         context.stroke();
 
-        var label = makeDiv(tick[2]);
+        var label = makeDiv(tick[2], 'y');
         var top = (y - this.attr_('axisLabelFontSize') / 2);
         if (top < 0) top = 0;
 
@@ -620,7 +621,7 @@ DygraphCanvasRenderer.prototype._renderAxis = function() {
         context.closePath();
         context.stroke();
 
-        var label = makeDiv(tick[1]);
+        var label = makeDiv(tick[1], 'x');
         label.style.textAlign = "center";
         label.style.top = (y + this.attr_('axisTickSize')) + 'px';
 
@@ -1002,6 +1003,10 @@ DygraphCanvasRenderer.prototype._renderLineChart = function() {
     }
   }
 
+  var isNullOrNaN = function(x) {
+    return (x === null || isNaN(x));
+  };
+
   for (var i = 0; i < setCount; i++) {
     var setName = setNames[i];
     var color = this.colors[setName];
@@ -1017,7 +1022,7 @@ DygraphCanvasRenderer.prototype._renderLineChart = function() {
     for (var j = 0; j < points.length; j++) {
       var point = points[j];
       if (point.name == setName) {
-        if (!Dygraph.isOK(point.canvasy)) {
+        if (isNullOrNaN(point.canvasy)) {
           if (stepPlot && prevX != null) {
             // Draw a horizontal line to the start of the missing data
             ctx.beginPath();
@@ -1033,9 +1038,9 @@ DygraphCanvasRenderer.prototype._renderLineChart = function() {
           // A point is "isolated" if it is non-null but both the previous
           // and next points are null.
           var isIsolated = (!prevX && (j == points.length - 1 ||
-                                       !Dygraph.isOK(points[j+1].canvasy)));
+                                       isNullOrNaN(points[j+1].canvasy)));
 
-          if (!prevX) {
+          if (prevX === null) {
             prevX = point.canvasx;
             prevY = point.canvasy;
           } else {