Merge pull request #548 from blcook223/range_sel_options
[dygraphs.git] / dygraph.js
index 6ae12c3..aaf4b39 100644 (file)
@@ -190,7 +190,7 @@ Dygraph.numberValueFormatter = function(x, opts) {
  * @private
  */
 Dygraph.numberAxisLabelFormatter = function(x, granularity, opts) {
-  return Dygraph.numberValueFormatter(x, opts);
+  return Dygraph.numberValueFormatter.call(this, x, opts);
 };
 
 /**
@@ -203,7 +203,7 @@ Dygraph.SHORT_MONTH_NAMES_ = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', '
 
 /**
  * Convert a JS date to a string appropriate to display on an axis that
- * is displaying values at the stated granularity. This respects the 
+ * is displaying values at the stated granularity. This respects the
  * labelsUTC option.
  * @param {Date} date The date to format
  * @param {number} granularity One of the Dygraph granularity constants
@@ -241,7 +241,7 @@ Dygraph.dateAxisLabelFormatter = function(date, granularity, opts) {
 Dygraph.dateAxisFormatter = Dygraph.dateAxisLabelFormatter;
 
 /**
- * Return a string version of a JS date for a value label. This respects the 
+ * Return a string version of a JS date for a value label. This respects the
  * labelsUTC option.
  * @param {Date} date The date to be formatted
  * @param {Dygraph} opts An options view
@@ -336,7 +336,14 @@ Dygraph.DEFAULT_ATTRS = {
   showRangeSelector: false,
   rangeSelectorHeight: 40,
   rangeSelectorPlotStrokeColor: "#808FAB",
+  rangeSelectorPlotFillGradientColor: "white",
   rangeSelectorPlotFillColor: "#A7B1C4",
+  rangeSelectorBackgroundStrokeColor: "gray",
+  rangeSelectorBackgroundLineWidth: 1,
+  rangeSelectorPlotLineWidth:1.5,
+  rangeSelectorForegroundStrokeColor: "black",
+  rangeSelectorForegroundLineWidth: 1,
+  rangeSelectorAlpha: 0.6,
   showInRangeSelector: null,
 
   // The ordering here ensures that central lines always appear above any
@@ -1986,7 +1993,7 @@ Dygraph.prototype.mouseMove_ = function(event) {
 };
 
 /**
- * Fetch left offset from the specified set index or if not passed, the 
+ * Fetch left offset from the specified set index or if not passed, the
  * first defined boundaryIds record (see bug #236).
  * @private
  */
@@ -2019,6 +2026,14 @@ Dygraph.prototype.animateSelection_ = function(direction) {
 
   var thisId = ++this.animateId;
   var that = this;
+  var cleanupIfClearing = function() {
+    // if we haven't reached fadeLevel 0 in the max frame time,
+    // ensure that the clear happens and just go to 0
+    if (that.fadeLevel !== 0 && direction < 0) {
+      that.fadeLevel = 0;
+      that.clearSelection();
+    }
+  };
   Dygraph.repeatAndCleanup(
     function(n) {
       // ignore simultaneous animations
@@ -2031,7 +2046,7 @@ Dygraph.prototype.animateSelection_ = function(direction) {
         that.updateSelection_(that.fadeLevel / totalSteps);
       }
     },
-    steps, millis, function() {});
+    steps, millis, cleanupIfClearing);
 };
 
 /**
@@ -2323,7 +2338,7 @@ Dygraph.prototype.getHandlerClass_ = function() {
  */
 Dygraph.prototype.predraw_ = function() {
   var start = new Date();
-  
+
   // Create the correct dataHandler
   this.dataHandler_ = new (this.getHandlerClass_())();
 
@@ -2361,7 +2376,7 @@ Dygraph.prototype.predraw_ = function() {
     if (this.rollPeriod_ > 1) {
       series = this.dataHandler_.rollingAverage(series, this.rollPeriod_, this.attributes_);
     }
-    
+
     this.rolledSeries_.push(series);
   }
 
@@ -2520,7 +2535,7 @@ Dygraph.prototype.gatherDatasets_ = function(rolledSeries, dateWindow) {
   var seriesIdx, sampleIdx;
   var firstIdx, lastIdx;
   var axisIdx;
-  
+
   // Loop over the fields (series).  Go from the last to the first,
   // because if they're stacked that's how we accumulate the values.
   var num_series = rolledSeries.length - 1;
@@ -2538,7 +2553,7 @@ Dygraph.prototype.gatherDatasets_ = function(rolledSeries, dateWindow) {
 
       // TODO(danvk): do binary search instead of linear search.
       // TODO(danvk): pass firstIdx and lastIdx directly to the renderer.
-      firstIdx = null; 
+      firstIdx = null;
       lastIdx = null;
       for (sampleIdx = 0; sampleIdx < series.length; sampleIdx++) {
         if (series[sampleIdx][0] >= low && firstIdx === null) {
@@ -2572,9 +2587,9 @@ Dygraph.prototype.gatherDatasets_ = function(rolledSeries, dateWindow) {
       if (correctedLastIdx !== lastIdx) {
         lastIdx = correctedLastIdx;
       }
-      
+
       boundaryIds[seriesIdx-1] = [firstIdx, lastIdx];
-      
+
       // .slice's end is exclusive, we want to include lastIdx.
       series = series.slice(firstIdx, lastIdx + 1);
     } else {
@@ -2583,10 +2598,10 @@ Dygraph.prototype.gatherDatasets_ = function(rolledSeries, dateWindow) {
     }
 
     var seriesName = this.attr_("labels")[seriesIdx];
-    var seriesExtremes = this.dataHandler_.getExtremeYValues(series, 
+    var seriesExtremes = this.dataHandler_.getExtremeYValues(series,
         dateWindow, this.getBooleanOption("stepPlot",seriesName));
 
-    var seriesPoints = this.dataHandler_.seriesToPoints(series, 
+    var seriesPoints = this.dataHandler_.seriesToPoints(series,
         seriesName, boundaryIds[seriesIdx-1][0]);
 
     if (this.getBooleanOption("stackedGraph")) {
@@ -2801,7 +2816,7 @@ Dygraph.prototype.computeYAxisRanges_ = function(extremes) {
   };
   var numAxes = this.attributes_.numAxes();
   var ypadCompat, span, series, ypad;
-  
+
   var p_axis;
 
   // Compute extreme values, a span and tick marks for each axis.
@@ -2927,8 +2942,8 @@ Dygraph.prototype.computeYAxisRanges_ = function(extremes) {
     } else {
       axis.computedValueRange = axis.extremeRange;
     }
-    
-    
+
+
     if (independentTicks) {
       axis.independentTicks = independentTicks;
       var opts = this.optionsViewForAxis_('y' + (i ? '2' : ''));
@@ -2950,7 +2965,7 @@ Dygraph.prototype.computeYAxisRanges_ = function(extremes) {
   // independent ticks, then that is permissible as well.
   for (var i = 0; i < numAxes; i++) {
     var axis = this.axes_[i];
-    
+
     if (!axis.independentTicks) {
       var opts = this.optionsViewForAxis_('y' + (i ? '2' : ''));
       var ticker = opts('ticker');
@@ -3594,19 +3609,25 @@ Dygraph.prototype.visibility = function() {
 };
 
 /**
- * Changes the visiblity of a series.
+ * Changes the visibility of one or more series.
  *
- * @param {number} num the series index
+ * @param {number|number[]} num the series index or an array of series indices
  * @param {boolean} value true or false, identifying the visibility.
  */
 Dygraph.prototype.setVisibility = function(num, value) {
   var x = this.visibility();
-  if (num < 0 || num >= x.length) {
-    console.warn("invalid series number in setVisibility: " + num);
-  } else {
-    x[num] = value;
-    this.predraw_();
+
+  if (num.constructor !== Array) num = [num];
+
+  for (var i = 0; i < num.length; i++) {
+    if (num[i] < 0 || num[i] >= x.length) {
+      console.warn("invalid series number in setVisibility: " + num[i]);
+    } else {
+      x[num[i]] = value;
+    }
   }
+
+  this.predraw_();
 };
 
 /**
@@ -3669,6 +3690,35 @@ Dygraph.prototype.indexFromSetName = function(name) {
 };
 
 /**
+ * Find the row number corresponding to the given x-value.
+ * Returns null if there is no such x-value in the data.
+ * If there are multiple rows with the same x-value, this will return the
+ * first one.
+ * @param {number} xVal The x-value to look for (e.g. millis since epoch).
+ * @return {?number} The row number, which you can pass to getValue(), or null.
+ */
+Dygraph.prototype.getRowForX = function(xVal) {
+  var low = 0,
+      high = this.numRows() - 1;
+
+  while (low <= high) {
+    var idx = (high + low) >> 1;
+    var x = this.getValue(idx, 0);
+    if (x < xVal) {
+      low = idx + 1;
+    } else if (x > xVal) {
+      high = idx - 1;
+    } else if (low != idx) {  // equal, but there may be an earlier match.
+      high = idx;
+    } else {
+      return idx;
+    }
+  }
+
+  return null;
+};
+
+/**
  * Trigger a callback when the dygraph has drawn itself and is ready to be
  * manipulated. This is primarily useful when dygraphs has to do an XHR for the
  * data (i.e. a URL is passed as the data source) and the chart is drawn