/**
* Convert a JS date to a string appropriate to display on an axis that
- * is displaying values at the stated granularity.
+ * is displaying values at the stated granularity. This respects the
+ * labelsDateUTC option.
* @param {Date} date The date to format
* @param {number} granularity One of the Dygraph granularity constants
- * @return {string} The formatted date
+ * @param {Dygraph} opts An options view
+ * @return {string} The date formatted as local time
* @private
*/
-Dygraph.dateAxisFormatter = function(date, granularity) {
+Dygraph.dateAxisLabelFormatter = function(date, granularity, opts) {
+ var utc = opts('labelsDateUTC');
+ var year, month, day, hours, mins, secs, millis;
+ if (utc) {
+ year = date.getUTCFullYear();
+ month = date.getUTCMonth();
+ day = date.getUTCDate();
+ hours = date.getUTCHours();
+ mins = date.getUTCMinutes();
+ secs = date.getUTCSeconds();
+ millis = date.getUTCMilliseconds();
+ } else {
+ year = date.getFullYear();
+ month = date.getMonth();
+ day = date.getDate();
+ hours = date.getHours();
+ mins = date.getMinutes();
+ secs = date.getSeconds();
+ millis = date.getMilliseconds();
+ }
if (granularity >= Dygraph.DECADAL) {
- return '' + date.getFullYear();
+ return '' + year;
} else if (granularity >= Dygraph.MONTHLY) {
- return Dygraph.SHORT_MONTH_NAMES_[date.getMonth()] + ' ' + date.getFullYear();
+ return Dygraph.SHORT_MONTH_NAMES_[month] + ' ' + Dygraph.zeropad(year);
} else {
- var frac = date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds() + date.getMilliseconds();
+ var frac = hours * 3600 + mins * 60 + secs + 1e-3 * millis;
if (frac === 0 || granularity >= Dygraph.DAILY) {
// e.g. '21Jan' (%d%b)
- var nd = new Date(date.getTime() + 3600*1000);
- return Dygraph.zeropad(nd.getDate()) + Dygraph.SHORT_MONTH_NAMES_[nd.getMonth()];
+ return Dygraph.zeropad(day) + Dygraph.SHORT_MONTH_NAMES_[month];
} else {
- return Dygraph.hmsString_(date.getTime());
+ return Dygraph.hmsString_(hours, mins, secs);
}
}
};
/**
+ * Return a string version of a JS date for a value label. This respects the
+ * labelsDateUTC option.
+ * @param {Date} date The date to be formatted
+ * @param {Dygraph} opts An options view
+ * @private
+ */
+Dygraph.dateValueFormatter = function(d, opts) {
+ return Dygraph.dateString_(d, opts('labelsDateUTC'));
+};
+
+/**
* Standard plotters. These may be used by clients.
* Available plotters are:
* - Dygraph.Plotters.linePlotter: draws central lines (most common)
customBars: false,
fillGraph: false,
fillAlpha: 0.15,
- fillStepPlot: false,
connectSeparatedPoints: false,
stackedGraph: false,
axes: {
x: {
pixelsPerLabel: 60,
- axisLabelFormatter: Dygraph.dateAxisFormatter,
- valueFormatter: Dygraph.dateString_,
+ axisLabelFormatter: Dygraph.dateAxisLabelFormatter,
+ valueFormatter: Dygraph.dateValueFormatter,
drawGrid: true,
drawAxis: true,
independentTicks: true,
// TODO(danvk): any other styles that are useful to set here?
this.graphDiv.style.textAlign = 'left'; // This is a CSS "reset"
+ this.graphDiv.style.position = 'relative';
enclosing.appendChild(this.graphDiv);
// Create the canvas for interactive parts of the chart.
this.lastRow_ = row;
for (var setIdx = 0; setIdx < this.layout_.points.length; ++setIdx) {
var points = this.layout_.points[setIdx];
+ // Check if the point at the appropriate index is the point we're looking
+ // for. If it is, just use it, otherwise search the array for a point
+ // in the proper place.
var setRow = row - this.getLeftBoundary_(setIdx);
- if (setRow < points.length) {
+ if (setRow < points.length && points[setRow].idx == row) {
var point = points[setRow];
if (point.yval !== null) this.selPoints_.push(point);
+ } else {
+ for (var pointIdx = 0; pointIdx < points.length; ++pointIdx) {
+ var point = points[pointIdx];
+ if (point.idx == row) {
+ if (point.yval !== null) {
+ this.selPoints_.push(point);
+ }
+ break;
+ }
+ }
}
}
} else {
var extremes = {}; // series name -> [low, high]
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.
seriesName, boundaryIds[seriesIdx-1][0]);
if (this.getBooleanOption("stackedGraph")) {
- Dygraph.stackPoints_(seriesPoints, cumulativeYval, seriesExtremes,
+ axisIdx = this.attributes_.axisForSeries(seriesName);
+ if (cumulativeYval[axisIdx] === undefined) {
+ cumulativeYval[axisIdx] = [];
+ }
+ Dygraph.stackPoints_(seriesPoints, cumulativeYval[axisIdx], seriesExtremes,
this.getBooleanOption("stackedGraphNaNFill"));
}
Dygraph.prototype.setXAxisOptions_ = function(isDate) {
if (isDate) {
this.attrs_.xValueParser = Dygraph.dateParser;
- this.attrs_.axes.x.valueFormatter = Dygraph.dateString_;
+ this.attrs_.axes.x.valueFormatter = Dygraph.dateValueFormatter;
this.attrs_.axes.x.ticker = Dygraph.dateTicker;
- this.attrs_.axes.x.axisLabelFormatter = Dygraph.dateAxisFormatter;
+ this.attrs_.axes.x.axisLabelFormatter = Dygraph.dateAxisLabelFormatter;
} else {
/** @private (shut up, jsdoc!) */
this.attrs_.xValueParser = function(x) { return parseFloat(x); };
if (Dygraph.isDateLike(data[0][0])) {
// Some intelligent defaults for a date x-axis.
- this.attrs_.axes.x.valueFormatter = Dygraph.dateString_;
+ this.attrs_.axes.x.valueFormatter = Dygraph.dateValueFormatter;
this.attrs_.axes.x.ticker = Dygraph.dateTicker;
- this.attrs_.axes.x.axisLabelFormatter = Dygraph.dateAxisFormatter;
+ this.attrs_.axes.x.axisLabelFormatter = Dygraph.dateAxisLabelFormatter;
// Assume they're all dates.
var parsedData = Dygraph.clone(data);
var indepType = data.getColumnType(0);
if (indepType == 'date' || indepType == 'datetime') {
this.attrs_.xValueParser = Dygraph.dateParser;
- this.attrs_.axes.x.valueFormatter = Dygraph.dateString_;
+ this.attrs_.axes.x.valueFormatter = Dygraph.dateValueFormatter;
this.attrs_.axes.x.ticker = Dygraph.dateTicker;
- this.attrs_.axes.x.axisLabelFormatter = Dygraph.dateAxisFormatter;
+ this.attrs_.axes.x.axisLabelFormatter = Dygraph.dateAxisLabelFormatter;
} else if (indepType == 'number') {
this.attrs_.xValueParser = function(x) { return parseFloat(x); };
this.attrs_.axes.x.valueFormatter = function(x) { return x; };