merge master
[dygraphs.git] / dygraph.js
index 623acf7..fe677f2 100644 (file)
@@ -193,6 +193,11 @@ Dygraph.DEFAULT_ATTRS = {
   stepPlot: false,
   avoidMinZero: false,
 
+  // Sizes of the various chart labels.
+  titleHeight: 28,
+  xLabelHeight: 18,
+  yLabelWidth: 18,
+
   interactionModel: null  // will be set to Dygraph.defaultInteractionModel.
 };
 
@@ -959,8 +964,9 @@ Dygraph.prototype.createStatusMessage_ = function() {
 };
 
 /**
- * Position the labels div so that its right edge is flush with the right edge
- * of the charting area.
+ * Position the labels div so that:
+ * - its right edge is flush with the right edge of the charting area
+ * - its top edge is flush with the top edge of the charting area
  */
 Dygraph.prototype.positionLabelsDiv_ = function() {
   // Don't touch a user-specified labelsDiv.
@@ -969,6 +975,7 @@ Dygraph.prototype.positionLabelsDiv_ = function() {
   var area = this.plotter_.area;
   var div = this.attr_("labelsDiv");
   div.style.left = area.x + area.w - this.attr_("labelsDivWidth") - 1 + "px";
+  div.style.top = area.y + "px";
 };
 
 /**
@@ -986,10 +993,11 @@ Dygraph.prototype.createRollInterface_ = function() {
 
   var display = this.attr_('showRoller') ? 'block' : 'none';
 
+  var area = this.plotter_.area;
   var textAttr = { "position": "absolute",
                    "zIndex": 10,
-                   "top": (this.plotter_.area.h - 25) + "px",
-                   "left": (this.plotter_.area.x + 1) + "px",
+                   "top": (area.y + area.h - 25) + "px",
+                   "left": (area.x + 1) + "px",
                    "display": display
                   };
   this.roller_.size = "2";
@@ -2112,7 +2120,7 @@ Dygraph.prototype.GetXAxis = function(start_time, end_time, granularity) {
       if (i % year_mod != 0) continue;
       for (var j = 0; j < months.length; j++) {
         var date_str = i + "/" + zeropad(1 + months[j]) + "/01";
-        var t = Date.parse(date_str);
+        var t = Dygraph.dateStrToMillis(date_str);
         if (t < start_time || t > end_time) continue;
         ticks.push({ v:t, label: formatter(new Date(t), granularity) });
       }
@@ -2601,13 +2609,10 @@ Dygraph.prototype.drawGraph_ = function() {
     this.layout_.addDataset(this.attr_("labels")[i], datasets[i]);
   }
 
-  if (datasets.length > 0) {
-    // TODO(danvk): this method doesn't need to return anything.
-    this.computeYAxisRanges_(extremes);
-    this.layout_.updateOptions( { yAxes: this.axes_,
-                                  seriesToAxisMap: this.seriesToAxisMap_
-                                } );
-  }
+  this.computeYAxisRanges_(extremes);
+  this.layout_.updateOptions( { yAxes: this.axes_,
+                                seriesToAxisMap: this.seriesToAxisMap_
+                              } );
   this.addXTicks_();
 
   // Save the X axis zoomed status as the updateOptions call will tend to set it errorneously
@@ -2793,23 +2798,18 @@ Dygraph.prototype.computeYAxisRanges_ = function(extremes) {
         // Only use valid extremes to stop null data series' from corrupting the scale.
         extremeMinY = extremes[series[j]][0];
         if (extremeMinY != null) {
-            minY = Math.min(extremeMinY, minY);
+          minY = Math.min(extremeMinY, minY);
         }
         extremeMaxY = extremes[series[j]][1];
         if (extremeMaxY != null) {
-            maxY = Math.max(extremeMaxY, maxY);
+          maxY = Math.max(extremeMaxY, maxY);
         }
       }
       if (axis.includeZero && minY > 0) minY = 0;
 
       // Ensure we have a valid scale, otherwise defualt to zero for safety.
-      if (minY == Infinity) {
-        minY = 0;
-      }
-
-      if (maxY == -Infinity) {
-        maxY = 0;
-      }
+      if (minY == Infinity) minY = 0;
+      if (maxY == -Infinity) maxY = 0;
 
       // Add some padding and round up to an integer to be human-friendly.
       var span = maxY - minY;
@@ -3035,16 +3035,16 @@ Dygraph.dateParser = function(dateStr, self) {
     while (dateStrSlashed.search("-") != -1) {
       dateStrSlashed = dateStrSlashed.replace("-", "/");
     }
-    d = Date.parse(dateStrSlashed);
+    d = Dygraph.dateStrToMillis(dateStrSlashed);
   } else if (dateStr.length == 8) {  // e.g. '20090712'
     // TODO(danvk): remove support for this format. It's confusing.
     dateStrSlashed = dateStr.substr(0,4) + "/" + dateStr.substr(4,2)
                        + "/" + dateStr.substr(6,2);
-    d = Date.parse(dateStrSlashed);
+    d = Dygraph.dateStrToMillis(dateStrSlashed);
   } else {
     // Any format that Date.parse will accept, e.g. "2009/07/12" or
     // "2009/07/12 12:34:56"
-    d = Date.parse(dateStr);
+    d = Dygraph.dateStrToMillis(dateStr);
   }
 
   if (!d || isNaN(d)) {
@@ -3431,6 +3431,13 @@ Dygraph.prototype.parseDataTable_ = function(data) {
   }
 }
 
+// This is identical to JavaScript's built-in Date.parse() method, except that
+// it doesn't get replaced with an incompatible method by aggressive JS
+// libraries like MooTools or Joomla.
+Dygraph.dateStrToMillis = function(str) {
+  return new Date(str).getTime();
+};
+
 // These functions are all based on MochiKit.
 Dygraph.update = function (self, o) {
   if (typeof(o) != 'undefined' && o !== null) {
@@ -3526,11 +3533,6 @@ Dygraph.prototype.start_ = function() {
  * <li>errorBars: changes whether the data contains stddev</li>
  * </ul>
  *
- * If the dateWindow or valueRange options are specified, the relevant zoomed_x_
- * or zoomed_y_ flags are set, unless the isZoomedIgnoreProgrammaticZoom option is also
- * secified. This allows for the chart to be programmatically zoomed without
- * altering the zoomed flags.
- *
  * @param {Object} attrs The new properties and values
  */
 Dygraph.prototype.updateOptions = function(attrs) {
@@ -4170,7 +4172,7 @@ Dygraph.OPTIONS_REFERENCE =  // <JSON>
   "sigma": {
     "default": "2.0",
     "labels": ["Error Bars"],
-    "type": "integer",
+    "type": "float",
     "description": "When errorBars is set, shade this many standard deviations above/below each point."
   },
   "customBars": {
@@ -4204,17 +4206,54 @@ Dygraph.OPTIONS_REFERENCE =  // <JSON>
     "default": "null",
     "description": "A value representing the farthest a graph may be panned, in percent of the display. For example, a value of 0.1 means that the graph can only be panned 10% pased the edges of the displayed values. null means no bounds."
   },
+  "title": {
+    "labels": ["Chart labels"],
+    "type": "string",
+    "default": "null",
+    "description": "Text to display above the chart. You can supply any HTML for this value, not just text. If you wish to style it using CSS, use the 'dygraph-label' or 'dygraph-title' classes."
+  },
+  "titleHeight": {
+    "default": "18",
+    "labels": ["Chart labels"],
+    "type": "integer",
+    "description": "Height of the chart title, in pixels. This also controls the default font size of the title. If you style the title on your own, this controls how much space is set aside above the chart for the title's div."
+  },
+  "xlabel": {
+    "labels": ["Chart labels"],
+    "type": "string",
+    "default": "null",
+    "description": "Text to display below the chart's x-axis. You can supply any HTML for this value, not just text. If you wish to style it using CSS, use the 'dygraph-label' or 'dygraph-xlabel' classes."
+  },
+  "xLabelHeight": {
+    "labels": ["Chart labels"],
+    "type": "integer",
+    "default": "18",
+    "description": "Height of the x-axis label, in pixels. This also controls the default font size of the x-axis label. If you style the label on your own, this controls how much space is set aside below the chart for the x-axis label's div."
+  },
+  "ylabel": {
+    "labels": ["Chart labels"],
+    "type": "string",
+    "default": "null",
+    "description": "Text to display to the left of the chart's y-axis. You can supply any HTML for this value, not just text. If you wish to style it using CSS, use the 'dygraph-label' or 'dygraph-ylabel' classes. The text will be rotated 90 degrees by default, so CSS rules may behave in unintuitive ways. No additional space is set aside for a y-axis label. If you need more space, increase the width of the y-axis tick labels using the yAxisLabelWidth option. If you need a wider div for the y-axis label, either style it that way with CSS (but remember that it's rotated, so width is controlled by the 'height' property) or set the yLabelWidth option."
+  },
+  "yLabelWidth": {
+    "labels": ["Chart labels"],
+    "type": "integer",
+    "default": "18",
+    "description": "Width of the div which contains the y-axis label. Since the y-axis label appears rotated 90 degrees, this actually affects the height of its div."
+  },
   "isZoomedIgnoreProgrammaticZoom" : {
     "default": "false",
     "labels": ["Zooming"],
     "type": "boolean",
-    "description" : "When this flag is passed along with either the <code>dateWindow</code> or <code>valueRange</code> options, the zoom flags are not changed to reflect a zoomed state. This is primarily useful for when the display area of a chart is changed programmatically and also where manual zooming is allowed and use is made of the <code>isZoomed</code> method to determine this."
+    "description" : "When this option is passed to updateOptions() along with either the <code>dateWindow</code> or <code>valueRange</code> options, the zoom flags are not changed to reflect a zoomed state. This is primarily useful for when the display area of a chart is changed programmatically and also where manual zooming is allowed and use is made of the <code>isZoomed</code> method to determine this."
   }
 }
 ;  // </JSON>
 // NOTE: in addition to parsing as JS, this snippet is expected to be valid
 // JSON. This assumption cannot be checked in JS, but it will be checked when
-// documentation is generated by the generate-documentation.py script.
+// documentation is generated by the generate-documentation.py script. For the
+// most part, this just means that you should always use double quotes.
 
 // Do a quick sanity check on the options reference.
 (function() {
@@ -4223,6 +4262,7 @@ Dygraph.OPTIONS_REFERENCE =  // <JSON>
   var valid_cats = [ 
    'Annotations',
    'Axis display',
+   'Chart labels',
    'CSV parsing',
    'Callbacks',
    'Data Line display',
@@ -4233,7 +4273,8 @@ Dygraph.OPTIONS_REFERENCE =  // <JSON>
    'Legend',
    'Overall display',
    'Rolling Averages',
-   'Value display/formatting'
+   'Value display/formatting',
+   'Zooming'
   ];
   var cats = {};
   for (var i = 0; i < valid_cats.length; i++) cats[valid_cats[i]] = true;