Merge branch 'master' of github.com:kberg/dygraphs into axis-label-font-size
authorRobert Konigsberg <konigsberg@gmail.com>
Mon, 31 Dec 2012 20:11:11 +0000 (15:11 -0500)
committerRobert Konigsberg <konigsberg@gmail.com>
Mon, 31 Dec 2012 20:11:11 +0000 (15:11 -0500)
Conflicts:
auto_tests/tests/axis_labels.js

auto_tests/tests/Util.js
auto_tests/tests/axis_labels.js
dygraph-options.js
dygraph.js
experimental/palette/options.js
plugins/axes.js

index 3eb59e3..08cc88a 100644 (file)
@@ -58,26 +58,13 @@ Util.getLegend = function(parent) {
 };
 
 /**
- * Assert that all the elements in 'parent' with class 'className' is
- * the expected font size.
+ * Assert that all elements have a certain style property.
  */
-Util.assertFontSizes = function(parent, className, expectedSize) {
-  var expectedSizePx = expectedSize + "px";
-  var labels = parent.getElementsByClassName(className);
-  assertTrue(labels.length > 0);
-
-  // window.getComputedStyle is apparently compatible with all browsers
-  // (IE first became compatible with IE9.)
-  // If this test fails on earlier browsers, then enable something like this,
-  // because the font size is set by the parent div.
-  // if (!window.getComputedStyle) {
-  //   fontSize = label.parentElement.style.fontSize;
-  // }
-  for (var idx = 0; idx < labels.length; idx++) {
-    var label = labels[idx];
-    var fontSize = window.getComputedStyle(label).fontSize;
-    assertEquals(expectedSizePx, fontSize);
-  }
+Util.assertStyleOfChildren = function(selector, property, expectedValue) {
+  assertTrue(selector.length > 0);
+  $.each(selector, function(idx, child) {
+    assertEquals(expectedValue,  $(child).css(property));
+  });
 };
 
 
index 56ddf3d..fabe1d2 100644 (file)
@@ -569,72 +569,52 @@ AxisLabelsTestCase.prototype.testIncludeZero = function() {
 AxisLabelsTestCase.prototype.testAxisLabelFontSize = function() {
   var graph = document.getElementById("graph");
   var g = new Dygraph(graph, AxisLabelsTestCase.simpleData, {});
-  var assertSize = function(className, size) {
-    var sizePx = size + "px";
-    var labels = graph.getElementsByClassName(className);
-    assertTrue(labels.length > 0);
-    // window.getComputedStyle is apparently compatible with all browsers
-    // (IE first became compatible with IE9.)
-    // If this test fails on earlier browsers, then enable something like this,
-    // because the font size is set by the parent div.
-    // if (!window.getComputedStyle) {
-    //   fontSize = label.parentElement.style.fontSize;
-    // }
-    for (var idx = 0; idx < labels.length; idx++) {
-      var label = labels[idx];
-      var fontSize = window.getComputedStyle(label).fontSize;
-      assertEquals(sizePx, fontSize);
-    }
-  }
 
   // Be sure we're dealing with a 14-point default.
   assertEquals(14, Dygraph.DEFAULT_ATTRS.axisLabelFontSize);
 
-  assertSize("dygraph-axis-label-x", 14);
-  assertSize("dygraph-axis-label-y", 14);
+  var assertFontSize = function(selector, expected) {
+    Util.assertStyleOfChildren(selector, "font-size", expected);
+  }
+  
+  assertFontSize($(".dygraph-axis-label-x"), "14px");
+  assertFontSize($(".dygraph-axis-label-y") , "14px");
 
   g.updateOptions({ axisLabelFontSize : 8});
-  assertSize("dygraph-axis-label-x", 8);
-  assertSize("dygraph-axis-label-y", 8);
-
-/*
- Enable these tests when https://code.google.com/p/dygraphs/issues/detail?id=126
- is fixed.
+  assertFontSize($(".dygraph-axis-label-x"), "8px"); 
+  assertFontSize($(".dygraph-axis-label-y"), "8px"); 
 
   g.updateOptions({
     axisLabelFontSize : null,
-    axes : {
+    axes : { 
       x : { axisLabelFontSize : 5 },
-    }
-  });
+    }   
+  }); 
 
-  assertSize("dygraph-axis-label-x", 5);
-  assertSize("dygraph-axis-label-y", 14);
+  assertFontSize($(".dygraph-axis-label-x"), "5px"); 
+  assertFontSize($(".dygraph-axis-label-y"), "14px");
 
   g.updateOptions({
-    axisLabelFontSize : null,
-    axes : {
-      y : { axisLabelFontSize : 3 },
-    }
-  });
+    axes : { 
+      y : { axisLabelFontSize : 20 },
+    }   
+  }); 
 
-  assertSize("dygraph-axis-label-x", 5);
-  assertSize("dygraph-axis-label-y", 3);
+  assertFontSize($(".dygraph-axis-label-x"), "5px"); 
+  assertFontSize($(".dygraph-axis-label-y"), "20px"); 
 
   g.updateOptions({
-    series : {
+    series : { 
       Y2 : { axis : "y2" } // copy y2 series to y2 axis.
-    },
-    axes : {
-      y2 : { axisLabelFontSize : 8 },
-    }
-  });
-
-  assertSize("dygraph-axis-label-x", 5);
-  assertSize("dygraph-axis-label-y", 3);
-  assertSize("dygraph-axis-label-y2", 8);
-*/
+    },  
+    axes : { 
+      y2 : { axisLabelFontSize : 12 },
+    }   
+  }); 
+
+  assertFontSize($(".dygraph-axis-label-x"), "5px"); 
+  assertFontSize($(".dygraph-axis-label-y1"), "20px"); 
+  assertFontSize($(".dygraph-axis-label-y2"), "12px"); 
 }
 
 AxisLabelsTestCase.prototype.testAxisLabelFontSizeNull = function() {
@@ -644,9 +624,82 @@ AxisLabelsTestCase.prototype.testAxisLabelFontSizeNull = function() {
       axisLabelFontSize: null
     });
 
+  var assertFontSize = function(selector, expected) {
+    Util.assertStyleOfChildren(selector, "font-size", expected);
+  }
+
+  // Be sure we're dealing with a 14-point default.
+  assertEquals(14, Dygraph.DEFAULT_ATTRS.axisLabelFontSize);
+
+  assertFontSize($(".dygraph-axis-label-x"), "14px");
+  assertFontSize($(".dygraph-axis-label-y"), "14px");
+}
+
+AxisLabelsTestCase.prototype.testAxisLabelColor = function() {
+  var graph = document.getElementById("graph");
+  var g = new Dygraph(graph, AxisLabelsTestCase.simpleData, {});
+
+  // Be sure we're dealing with a black default.
+  assertEquals("black", Dygraph.DEFAULT_ATTRS.axisLabelColor);
+
+  var assertColor = function(selector, expected) {
+    Util.assertStyleOfChildren(selector, "color", expected);
+  }
+
+  assertColor($(".dygraph-axis-label-x"), "rgb(0, 0, 0)");
+  assertColor($(".dygraph-axis-label-y"), "rgb(0, 0, 0)");
+
+  g.updateOptions({ axisLabelColor : "red"});
+  assertColor($(".dygraph-axis-label-x"), "rgb(255, 0, 0)"); 
+  assertColor($(".dygraph-axis-label-y"), "rgb(255, 0, 0)"); 
+
+  g.updateOptions({
+    axisLabelColor : null,
+    axes : { 
+      x : { axisLabelColor : "blue" },
+    }   
+  }); 
+
+  assertColor($(".dygraph-axis-label-x"), "rgb(0, 0, 255)"); 
+  assertColor($(".dygraph-axis-label-y"), "rgb(0, 0, 0)");
+
+  g.updateOptions({
+    axes : { 
+      y : { axisLabelColor : "green" },
+    }   
+  }); 
+
+  assertColor($(".dygraph-axis-label-x"), "rgb(0, 0, 255)"); 
+  assertColor($(".dygraph-axis-label-y"), "rgb(0, 128, 0)"); 
+
+  g.updateOptions({
+    series : { 
+      Y2 : { axis : "y2" } // copy y2 series to y2 axis.
+    },  
+    axes : { 
+      y2 : { axisLabelColor : "yellow" },
+    }   
+  }); 
+
+  assertColor($(".dygraph-axis-label-x"), "rgb(0, 0, 255)"); 
+  assertColor($(".dygraph-axis-label-y1"), "rgb(0, 128, 0)"); 
+  assertColor($(".dygraph-axis-label-y2"), "rgb(255, 255, 0)"); 
+}
+
+AxisLabelsTestCase.prototype.testAxisLabelColorNull = function() {
+  var graph = document.getElementById("graph");
+  var g = new Dygraph(graph, AxisLabelsTestCase.simpleData,
+    {
+      axisLabelColor: null
+    });
+
+  var assertColor = function(selector, expected) {
+    Util.assertStyleOfChildren(selector, "color", expected);
+  }
+
   // Be sure we're dealing with a 14-point default.
   assertEquals(14, Dygraph.DEFAULT_ATTRS.axisLabelFontSize);
 
-  Util.assertFontSizes(graph, "dygraph-axis-label-x", 14);
-  Util.assertFontSizes(graph, "dygraph-axis-label-y", 14);
+  assertColor($(".dygraph-axis-label-x"), "rgb(0, 0, 0)");
+  assertColor($(".dygraph-axis-label-y"), "rgb(0, 0, 0)");
 }
index f059ff9..81f7667 100644 (file)
@@ -11,7 +11,8 @@
  * dygraph_ - the graph.
  * global_ - global attributes (common among all graphs, AIUI)
  * user - attributes set by the user
- * axes_ - array of axis index to { series : [ series names ] , options : { axis-specific options. }
+ * yAxes_ - array of axis index to { series : [ series names ] , options : { axis-specific options. }
+ * xAxis_ - { options : { axis-specific options. }
  * series_ - { seriesName -> { idx, yAxis, options }}
  * labels_ - used as mapping from index to series name.
  */
@@ -28,7 +29,8 @@
  */
 var DygraphOptions = function(dygraph) {
   this.dygraph_ = dygraph;
-  this.axes_ = [];
+  this.yAxes_ = [];
+  this.xAxis_ = {};
   this.series_ = {};
 
   // Once these two objects are initialized, you can call get();
@@ -92,7 +94,8 @@ DygraphOptions.axisToIndex_ = function(axis) {
 DygraphOptions.prototype.reparseSeries = function() {
   this.labels = this.get("labels").slice(1);
 
-  this.axes_ = [ { series : [], options : {}} ]; // Always one axis at least.
+  this.yAxes_ = [ { series : [], options : {}} ]; // Always one axis at least.
+  this.xAxis_ = { options : {} };
   this.series_ = {};
 
   // Traditionally, per-series options were specified right up there with the options. For instance
@@ -131,12 +134,12 @@ DygraphOptions.prototype.reparseSeries = function() {
       var axis = optionsForSeries["axis"];
       if (typeof(axis) == 'object') {
         yAxis = ++axisId;
-        this.axes_[yAxis] = { series : [ seriesName ], options : axis };
+        this.yAxes_[yAxis] = { series : [ seriesName ], options : axis };
       }
 
       // Associate series without axis options with axis 0.
       if (!axis) { // undefined
-        this.axes_[0].series.push(seriesName);
+        this.yAxes_[0].series.push(seriesName);
       }
 
       this.series_[seriesName] = { idx: idx, yAxis: yAxis, options : optionsForSeries };
@@ -157,7 +160,7 @@ DygraphOptions.prototype.reparseSeries = function() {
         }
         var yAxis = this.series_[axis].yAxis;
         this.series_[seriesName].yAxis = yAxis;
-        this.axes_[yAxis].series.push(seriesName);
+        this.yAxes_[yAxis].series.push(seriesName);
       }
     }
   } else {
@@ -171,20 +174,20 @@ DygraphOptions.prototype.reparseSeries = function() {
         yAxis: yAxis,
         options : optionsForSeries };
 
-      if (!this.axes_[yAxis]) {
-        this.axes_[yAxis] =  { series : [ seriesName ], options : {} };
+      if (!this.yAxes_[yAxis]) {
+        this.yAxes_[yAxis] =  { series : [ seriesName ], options : {} };
       } else {
-        this.axes_[yAxis].series.push(seriesName);
+        this.yAxes_[yAxis].series.push(seriesName);
       }
     }
   }
 
-  // This doesn't support reading from the 'x' axis, only 'y' and 'y2.
   var axis_opts = this.user_["axes"] || {};
-  Dygraph.update(this.axes_[0].options, axis_opts["y"] || {});
-  if (this.axes_.length > 1) {
-    Dygraph.update(this.axes_[1].options, axis_opts["y2"] || {});   
+  Dygraph.update(this.yAxes_[0].options, axis_opts["y"] || {});
+  if (this.yAxes_.length > 1) {
+    Dygraph.update(this.yAxes_[1].options, axis_opts["y2"] || {});   
   }
+  Dygraph.update(this.xAxis_.options, axis_opts["x"] || {});
 };
 
 /**
@@ -223,19 +226,35 @@ DygraphOptions.prototype.getGlobalDefault_ = function(name) {
  *
  * @param {String} name the name of the option.
  * @param {String|number} axis the axis to search. Can be the string representation
- * ("y", "y2") or the axis number (0, 1).
+ * ("x", "y", "y2") or the y-axis number (0, 1). (x-axis can't be specified by number.')
  */
 DygraphOptions.prototype.getForAxis = function(name, axis) {
-  var axisIdx = 0;
+  var axisIdx;
+  var axisString;
+
+  // Since axis can be a number or a string, straighten everything out here.
   if (typeof(axis) == 'number') {
     axisIdx = axis;
+    axisString = axisIdx == 0 ? "y" : "y2";
   } else {
-    // TODO(konigsberg): Accept only valid axis strings?
-    axisIdx = (axis == "y2") ? 1 : 0;
+    if (axis == "y1") { axis = "y"; } // Standardize on 'y'. Is this bad? I think so.
+    if (axis == "y") {
+      axisIdx = 0;
+    } else if (axis == "y2") {
+      axisIdx = 1;
+    } else if (axis == "x") {
+      axisIdx = -1; // simply a placeholder for below.
+    } else {
+      throw "Unknown axis " + axis;
+    }
+    axisString = axis;
   }
+
+  var userAxis = (axisIdx == -1) ? this.xAxis_ : this.yAxes_[axisIdx];
+
   // Search the user-specified axis option first.
-  if (this.axes_[axisIdx]) {
-    var axisOptions = this.axes_[axisIdx].options;
+  if (userAxis) { // This condition could be removed if we always set up this.yAxes_ for y2.
+    var axisOptions = userAxis.options;
     if (axisOptions.hasOwnProperty(name)) {
       return axisOptions[name];
     }
@@ -248,7 +267,6 @@ DygraphOptions.prototype.getForAxis = function(name, axis) {
   }
 
   // Default axis options third.
-  var axisString = axis == 0 ? "y" : "y2";
   var defaultAxisOptions = Dygraph.DEFAULT_ATTRS.axes[axisString];
   if (defaultAxisOptions.hasOwnProperty(name)) {
     return defaultAxisOptions[name];
@@ -294,7 +312,7 @@ DygraphOptions.prototype.getForSeries = function(name, series) {
  * @return {Number} the number of axes.
  */
 DygraphOptions.prototype.numAxes = function() {
-  return this.axes_.length;
+  return this.yAxes_.length;
 };
 
 /**
@@ -307,15 +325,16 @@ DygraphOptions.prototype.axisForSeries = function(seriesName) {
 /**
  * Returns the options for the specified axis.
  */
+// TODO(konigsberg): this is y-axis specific. Support the x axis.
 DygraphOptions.prototype.axisOptions = function(yAxis) {
-  return this.axes_[yAxis].options;
+  return this.yAxes_[yAxis].options;
 };
 
 /**
  * Return the series associated with an axis.
  */
 DygraphOptions.prototype.seriesForAxis = function(yAxis) {
-  return this.axes_[yAxis].series;
+  return this.yAxes_[yAxis].series;
 };
 
 /**
index 1ac7d43..4c8c65d 100644 (file)
@@ -598,6 +598,9 @@ Dygraph.prototype.getOption = function(name, opt_seriesName) {
   return this.attr_(name, opt_seriesName);
 };
 
+Dygraph.prototype.getOptionForAxis = function(name, axis) {
+  return this.attributes_.getForAxis(name, axis);
+}
 /**
  * @private
  * @param  String} axis The name of the axis (i.e. 'x', 'y' or 'y2')
index 7d15670..d627adf 100644 (file)
@@ -59,13 +59,17 @@ var opts = {
   avoidMinZero : {
     type : "boolean"
   },
+  axis : {
+    type : "string",
+    scope : [ "series" ]
+  },
   axisLabelColor : {
     type : "string",
-    // scope : [ "x", "y", "y2" ]
+    scope : [ "global", "x", "y", "y2" ]
   },
   axisLabelFontSize : {
     type : "int",
-    // scope : [ "x", "y", "y2" ]
+    scope : [ "global", "x", "y", "y2" ]
   },
   axisLabelFormatter : {
     type : "function(numberOrDate, granularity, opts, dygraph)",
index 1f9c256..2e1834c 100644 (file)
@@ -52,7 +52,7 @@ axes.prototype.layout = function(e) {
     if (g.getOption('xAxisHeight')) {
       h = g.getOption('xAxisHeight');
     } else {
-      h = g.getOption('axisLabelFontSize') + 2 * g.getOption('axisTickSize');
+      h = g.getOptionForAxis('axisLabelFontSize', 'x') + 2 * g.getOption('axisTickSize');
     }
     var x_axis_rect = e.reserveSpaceBottom(h);
   }
@@ -101,18 +101,34 @@ axes.prototype.willDrawChart = function(e) {
 
   var label, x, y, tick, i;
 
-  var labelStyle = {
-    position: "absolute",
-    fontSize: g.getOption('axisLabelFontSize') + "px",
-    zIndex: 10,
-    color: g.getOption('axisLabelColor'),
-    width: g.getOption('axisLabelWidth') + "px",
-    // height: this.attr_('axisLabelFontSize') + 2 + "px",
-    lineHeight: "normal",  // Something other than "normal" line-height screws up label positioning.
-    overflow: "hidden"
+  var makeLabelStyle = function(axis) {
+    return {
+      position: "absolute",
+      fontSize: g.getOptionForAxis('axisLabelFontSize', axis) + "px",
+      zIndex: 10,
+      color: g.getOptionForAxis('axisLabelColor', axis),
+      width: g.getOption('axisLabelWidth') + "px",
+      // height: g.getOptionForAxis('axisLabelFontSize', 'x') + 2 + "px",
+      lineHeight: "normal",  // Something other than "normal" line-height screws up label positioning.
+      overflow: "hidden"
+    };
+  }
+
+  var labelStyles = {
+    x : makeLabelStyle('x'),
+    y : makeLabelStyle('y'),
+    y2 : makeLabelStyle('y2'),
   };
+
   var makeDiv = function(txt, axis, prec_axis) {
+    /*
+     * This seems to be called with the following three sets of axis/perc_axis:
+     * x: undefined
+     * y: y1
+     * y: y2
+     */
     var div = document.createElement("div");
+    var labelStyle = labelStyles[prec_axis == 'y2' ? 'y2' : axis];
     for (var name in labelStyle) {
       if (labelStyle.hasOwnProperty(name)) {
         div.style[name] = labelStyle[name];
@@ -149,6 +165,7 @@ axes.prototype.willDrawChart = function(e) {
           sgn = -1;
           prec_axis = 'y2';
         }
+        var fontSize = g.getOptionForAxis('axisLabelFontSize', prec_axis);
         y = area.y + tick[1] * area.h;
 
         /* Tick marks are currently clipped, so don't bother drawing them.
@@ -160,10 +177,10 @@ axes.prototype.willDrawChart = function(e) {
         */
 
         label = makeDiv(tick[2], 'y', num_axes == 2 ? prec_axis : null);
-        var top = (y - g.getOption('axisLabelFontSize') / 2);
+        var top = (y - fontSize / 2);
         if (top < 0) top = 0;
 
-        if (top + g.getOption('axisLabelFontSize') + 3 > canvasHeight) {
+        if (top + fontSize + 3 > canvasHeight) {
           label.style.bottom = "0px";
         } else {
           label.style.top = top + "px";
@@ -185,7 +202,8 @@ axes.prototype.willDrawChart = function(e) {
       // tick on the x-axis. Shift the bottom tick up a little bit to
       // compensate if necessary.
       var bottomTick = this.ylabels_[0];
-      var fontSize = g.getOption('axisLabelFontSize');
+      // Interested in the y2 axis also?
+      var fontSize = g.getOptionForAxis('axisLabelFontSize', "y");
       var bottom = parseInt(bottomTick.style.top, 10) + fontSize;
       if (bottom > canvasHeight - fontSize) {
         bottomTick.style.top = (parseInt(bottomTick.style.top, 10) -