From 35b124b9c051c83e196f4476dfbb826466dd5a0e Mon Sep 17 00:00:00 2001 From: Joan Pau Beltran Date: Wed, 22 Jan 2014 13:55:51 +0100 Subject: [PATCH] Added support for UTC date time labels. * dygraph-utils.js: new utc switch parameter for `Dygraph.dateString_` and new signature for `Dygraph.hhmmss_`. * dygraph.js: support for UTC date time labels in date formatter. Also rename it to `dateAxisLabelFormatter` for homogeneity with the numeric one. and add a `dateValueFormatter`. * dygraph-options-reference.js: new `labelsDateUTC` option. --- dygraph-options-reference.js | 6 ++++ dygraph-utils.js | 67 +++++++++++++++++++++++++++----------------- dygraph.js | 66 ++++++++++++++++++++++++++++++++----------- 3 files changed, 96 insertions(+), 43 deletions(-) diff --git a/dygraph-options-reference.js b/dygraph-options-reference.js index 3ecc531..958a1ce 100644 --- a/dygraph-options-reference.js +++ b/dygraph-options-reference.js @@ -486,6 +486,12 @@ Dygraph.OPTIONS_REFERENCE = // "type": "boolean", "description": "When set, display the graph as a step plot instead of a line plot. This option may either be set for the whole graph or for single series." }, + "labelsDateUTC": { + "default": "false", + "labels": ["Value display/formatting"], + "type": "boolean", + "description": "Show date/time labels according to UTC (instead of local time)." + }, "labelsKMB": { "default": "false", "labels": ["Value display/formatting"], diff --git a/dygraph-utils.js b/dygraph-utils.js index 36ad10e..a5d3c26 100644 --- a/dygraph-utils.js +++ b/dygraph-utils.js @@ -477,45 +477,60 @@ Dygraph.zeropad = function(x) { /** * Return a string version of the hours, minutes and seconds portion of a date. - * - * @param {number} date The JavaScript date (ms since epoch) - * @return {string} A time of the form "HH:MM:SS" + * @param {number} hh The hours (from 0-23) + * @param {number} mm The minutes (from 0-59) + * @param {number} ss The seconds (from 0-59) + * @return {string} A time of the form "HH:MM" or "HH:MM:SS" * @private */ -Dygraph.hmsString_ = function(date) { +Dygraph.hmsString_ = function(hh, mm, ss) { var zeropad = Dygraph.zeropad; - var d = new Date(date); - if (d.getSeconds()) { - return zeropad(d.getHours()) + ":" + - zeropad(d.getMinutes()) + ":" + - zeropad(d.getSeconds()); - } else { - return zeropad(d.getHours()) + ":" + zeropad(d.getMinutes()); + var ret = zeropad(hh) + ":" + zeropad(mm); + if (ss) { + ret += ":" + zeropad(ss); } + return ret; }; /** - * Convert a JS date (millis since epoch) to YYYY/MM/DD + * Convert a JS date (millis since epoch) to a formatted string. * @param {number} date The JavaScript date (ms since epoch) - * @return {string} A date of the form "YYYY/MM/DD" + * @param {boolean} utc Wether output UTC or local time + * @return {string} A date of one of these forms: + * "YYYY/MM/DD", "YYYY/MM/DD HH:MM" or "YYYY/MM/DD HH:MM:SS" * @private */ -Dygraph.dateString_ = function(date) { +Dygraph.dateString_ = function(date, utc) { var zeropad = Dygraph.zeropad; - var d = new Date(date); - - // Get the year: - var year = "" + d.getFullYear(); + var dt = new Date(date); + var y, m, d, hh, mm, ss; + if (utc) { + y = dt.getUTCFullYear(); + m = dt.getUTCMonth(); + d = dt.getUTCDate(); + hh = dt.getUTCHours(); + mm = dt.getUTCMinutes(); + ss = dt.getUTCSeconds(); + } else { + y = dt.getFullYear(); + m = dt.getMonth(); + d = dt.getDate(); + hh = dt.getHours(); + mm = dt.getMinutes(); + ss = dt.getSeconds(); + } + // Get a year string: + var year = "" + y; // Get a 0 padded month string - var month = zeropad(d.getMonth() + 1); //months are 0-offset, sigh + var month = zeropad(m + 1); //months are 0-offset, sigh // Get a 0 padded day string - var day = zeropad(d.getDate()); - - var ret = ""; - var frac = d.getHours() * 3600 + d.getMinutes() * 60 + d.getSeconds(); - if (frac) ret = " " + Dygraph.hmsString_(date); - - return year + "/" + month + "/" + day + ret; + var day = zeropad(d); + var frac = hh * 3600 + mm * 60 + ss + var ret = year + "/" + month + "/" + day; + if (frac) { + ret += " " + Dygraph.hmsString_(hh,mm,ss); + } + return ret; }; /** diff --git a/dygraph.js b/dygraph.js index e6b971b..2a6f827 100644 --- a/dygraph.js +++ b/dygraph.js @@ -202,30 +202,62 @@ 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. + * 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] + ' ' + year; } else { - var frac = date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds() + date.getMilliseconds(); + // 1e-3 factor on millis missing in original implementation + 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); } } }; /** + * @private + * Return a string version of a JS date for a value label. This respects the + * labelsDateUTC option. + * @param {Date} date The number to be formatted + * @param {Dygraph} opts An options view + */ +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) @@ -335,8 +367,8 @@ Dygraph.DEFAULT_ATTRS = { axes: { x: { pixelsPerLabel: 60, - axisLabelFormatter: Dygraph.dateAxisFormatter, - valueFormatter: Dygraph.dateString_, + axisLabelFormatter: Dygraph.dateAxisLabelFormatter, + valueFormatter: Dygraph.dateValueFormatter, drawGrid: true, drawAxis: true, independentTicks: true, @@ -2908,9 +2940,9 @@ Dygraph.prototype.detectTypeFromString_ = function(str) { 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); }; @@ -3108,9 +3140,9 @@ Dygraph.prototype.parseArray_ = function(data) { 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); @@ -3167,9 +3199,9 @@ Dygraph.prototype.parseDataTable_ = function(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; }; -- 2.7.4