/**
* 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
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
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
};
/**
- * 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
*/
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
that.updateSelection_(that.fadeLevel / totalSteps);
}
},
- steps, millis, function() {});
+ steps, millis, cleanupIfClearing);
};
/**
*/
Dygraph.prototype.predraw_ = function() {
var start = new Date();
-
+
// Create the correct dataHandler
this.dataHandler_ = new (this.getHandlerClass_())();
if (this.rollPeriod_ > 1) {
series = this.dataHandler_.rollingAverage(series, this.rollPeriod_, this.attributes_);
}
-
+
this.rolledSeries_.push(series);
}
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;
// 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) {
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 {
}
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")) {
};
var numAxes = this.attributes_.numAxes();
var ypadCompat, span, series, ypad;
-
+
var p_axis;
// Compute extreme values, a span and tick marks for each axis.
} else {
axis.computedValueRange = axis.extremeRange;
}
-
-
+
+
if (independentTicks) {
axis.independentTicks = independentTicks;
var opts = this.optionsViewForAxis_('y' + (i ? '2' : ''));
// 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');
};
/**
- * 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_();
};
/**
};
/**
+ * 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