From 1e7f8af02c2ddc8320aa9b0aa98194c883b7b749 Mon Sep 17 00:00:00 2001 From: Joan Pau Beltran Date: Mon, 3 Nov 2014 16:45:33 +0100 Subject: [PATCH] Move date accessors to utils script and adapt tick generation and format. Add two properties to the `Dygraph` object to hold the date accessor methods according to either UTC or local time. Use these accessors to simplify a little bit the label format and the tick generation. --- dygraph-tickers.js | 140 +++++++++++++++-------------------------------------- dygraph-utils.js | 69 ++++++++++++++++++-------- 2 files changed, 87 insertions(+), 122 deletions(-) diff --git a/dygraph-tickers.js b/dygraph-tickers.js index 7b3dae1..8818466 100644 --- a/dygraph-tickers.js +++ b/dygraph-tickers.js @@ -343,80 +343,33 @@ Dygraph.getDateAxis = function(start_time, end_time, granularity, opts, dg) { var formatter = /** @type{AxisLabelFormatter} */( opts("axisLabelFormatter")); var utc = opts("labelsDateUTC"); - + var accessors = utc ? Dygraph.DateAccessorsUTC : Dygraph.DateAccessorsLocal; + var datefield = Dygraph.TICK_PLACEMENT[granularity].datefield; var step = Dygraph.TICK_PLACEMENT[granularity].step; var spacing = Dygraph.TICK_PLACEMENT[granularity].spacing; - - // Choose appropiate date methods according to UTC or local time option. - // weekday: return the day of week from a Date object. - // decompose_date: decompose a Date object into an array of datefields. - // compose_date: compose a Date object from an array of date fields. - var compose_date, decompose_date, weekday; - if (utc) { - weekday = function (d) { - return d.getUTCDay(); - }; - decompose_date = function (d) { - var a = []; - a[Dygraph.DATEFIELD_Y] = d.getUTCFullYear(); - a[Dygraph.DATEFIELD_M] = d.getUTCMonth(); - a[Dygraph.DATEFIELD_D] = d.getUTCDate(); - a[Dygraph.DATEFIELD_HH] = d.getUTCHours(); - a[Dygraph.DATEFIELD_MM] = d.getUTCMinutes(); - a[Dygraph.DATEFIELD_SS] = d.getUTCSeconds(); - a[Dygraph.DATEFIELD_MS] = d.getUTCMilliseconds(); - return a; - }; - compose_date = function (a) { - var d = new Date(Date.UTC(a[Dygraph.DATEFIELD_Y], - a[Dygraph.DATEFIELD_M], - a[Dygraph.DATEFIELD_D], - a[Dygraph.DATEFIELD_HH], - a[Dygraph.DATEFIELD_MM], - a[Dygraph.DATEFIELD_SS], - a[Dygraph.DATEFIELD_MS])); - return d; - }; - } else { - weekday = function(d) { - return d.getDay(); - }; - decompose_date = function (d) { - var a = []; - a[Dygraph.DATEFIELD_Y] = d.getFullYear(); - a[Dygraph.DATEFIELD_M] = d.getMonth(); - a[Dygraph.DATEFIELD_D] = d.getDate(); - a[Dygraph.DATEFIELD_HH] = d.getHours(); - a[Dygraph.DATEFIELD_MM] = d.getMinutes(); - a[Dygraph.DATEFIELD_SS] = d.getSeconds(); - a[Dygraph.DATEFIELD_MS] = d.getMilliseconds(); - return a; - }; - compose_date = function (a) { - var d = new Date(a[Dygraph.DATEFIELD_Y], - a[Dygraph.DATEFIELD_M], - a[Dygraph.DATEFIELD_D], - a[Dygraph.DATEFIELD_HH], - a[Dygraph.DATEFIELD_MM], - a[Dygraph.DATEFIELD_SS], - a[Dygraph.DATEFIELD_MS]); - return d; - }; - } - + // Choose a nice tick position before the initial instant. // Currently, this code deals properly with the existent daily granularities: // DAILY (with step of 1) and WEEKLY (with step of 7 but specially handled). // Other daily granularities (say TWO_DAILY) should also be handled specially // by setting the start_date_offset to 0. var start_date = new Date(start_time); - var date_array = decompose_date(start_date); + var date_array = []; + date_array[Dygraph.DATEFIELD_Y] = accessors.getFullYear(start_date); + date_array[Dygraph.DATEFIELD_M] = accessors.getMonth(start_date); + date_array[Dygraph.DATEFIELD_D] = accessors.getDate(start_date); + date_array[Dygraph.DATEFIELD_HH] = accessors.getHours(start_date); + date_array[Dygraph.DATEFIELD_MM] = accessors.getMinutes(start_date); + date_array[Dygraph.DATEFIELD_SS] = accessors.getSeconds(start_date); + date_array[Dygraph.DATEFIELD_MS] = accessors.getMilliseconds(start_date); + var start_date_offset = date_array[datefield] % step; if (granularity == Dygraph.WEEKLY) { // This will put the ticks on Sundays. - start_date_offset = weekday(start_date); + start_date_offset = accessors.getDay(start_date); } + date_array[datefield] -= start_date_offset; for (var df = datefield + 1; df < Dygraph.NUM_DATEFIELDS; df++) { // The minimum value is 1 for the day of month, and 0 for all other fields. @@ -434,56 +387,39 @@ Dygraph.getDateAxis = function(start_time, end_time, granularity, opts, dg) { // there are dates that do not represent any time value at all // (those in the hour skipped at the 'spring forward'), // and the JavaScript engines usually return an equivalent value. - // Hence we have to check that the date is effectively increased at each step, - // and that a tick should be place at the returned date. - // Since start_date is no later than start_time (but possibly equal), - // assuming a previous tick just before start_time removes an spurious - // tick outside the given time range. + // Hence we have to check that the date is properly increased at each step, + // returning a date at a nice tick position. var ticks = []; - var next_tick_date = compose_date(date_array); - var next_tick_time = next_tick_date.getTime(); - var prev_tick_time = start_time - 1; + var tick_date = accessors.makeDate.apply(null, date_array); + var tick_time = tick_date.getTime(); if (granularity <= Dygraph.HOURLY) { - while (next_tick_time <= end_time) { - if (next_tick_time > prev_tick_time) { - ticks.push({ v: next_tick_time, - label: formatter(next_tick_date, granularity, opts, dg) - }); - prev_tick_time = next_tick_time; - } - next_tick_time += spacing; - next_tick_date = new Date(next_tick_time); + if (tick_time < start_time) { + tick_time += spacing; + tick_date = new Date(tick_time); } - } else if (granularity < Dygraph.DAILY) { - var get_hours; - if (utc) { - get_hours = function (d) { return d.getUTCHours(); }; - } else { - get_hours = function (d) { return d.getHours(); }; + while (tick_time <= end_time) { + ticks.push({ v: tick_time, + label: formatter(tick_date, granularity, opts, dg) + }); + tick_time += spacing; + tick_date = new Date(tick_time); } - while (next_tick_time <= end_time) { - if (next_tick_time > prev_tick_time && - get_hours(next_tick_date) % step == 0) { - ticks.push({ v: next_tick_time, - label: formatter(next_tick_date, granularity, opts, dg) - }); - prev_tick_time = next_tick_time; - } + } else { + if (tick_time < start_time) { date_array[datefield] += step; - next_tick_date = compose_date(date_array); - next_tick_time = next_tick_date.getTime(); + tick_date = accessors.makeDate.apply(null, date_array); + tick_time = tick_date.getTime(); } - } else { - while (next_tick_time <= end_time) { - if (next_tick_time > prev_tick_time) { - ticks.push({ v: next_tick_time, - label: formatter(next_tick_date, granularity, opts, dg) + while (tick_time <= end_time) { + if (granularity >= Dygraph.DAILY || + accessors.getHours(tick_date) % step === 0) { + ticks.push({ v: tick_time, + label: formatter(tick_date, granularity, opts, dg) }); - prev_tick_time = next_tick_time; } date_array[datefield] += step; - next_tick_date = compose_date(date_array); - next_tick_time = next_tick_date.getTime(); + tick_date = accessors.makeDate.apply(null, date_array); + tick_time = tick_date.getTime(); } } return ticks; diff --git a/dygraph-utils.js b/dygraph-utils.js index 14aac18..9e74c7d 100644 --- a/dygraph-utils.js +++ b/dygraph-utils.js @@ -476,6 +476,44 @@ Dygraph.zeropad = function(x) { }; /** + * Date accessors to get the parts of a calendar date (year, month, + * day, hour, minute, second and millisecond) according to local time, + * and factory method to call the Date constructor with an array of arguments. + */ +Dygraph.DateAccessorsLocal = { + getFullYear: function(d) {return d.getFullYear();}, + getMonth: function(d) {return d.getMonth();}, + getDate: function(d) {return d.getDate();}, + getHours: function(d) {return d.getHours();}, + getMinutes: function(d) {return d.getMinutes();}, + getSeconds: function(d) {return d.getSeconds();}, + getMilliseconds: function(d) {return d.getMilliseconds();}, + getDay: function(d) {return d.getDay();}, + makeDate: function(y, m, d, hh, mm, ss, ms) { + return new Date(y, m, d, hh, mm, ss, ms); + } +}; + +/** + * Date accessors to get the parts of a calendar date (year, month, + * day of month, hour, minute, second and millisecond) according to UTC time, + * and factory method to call the Date constructor with an array of arguments. + */ +Dygraph.DateAccessorsUTC = { + getFullYear: function(d) {return d.getUTCFullYear();}, + getMonth: function(d) {return d.getUTCMonth();}, + getDate: function(d) {return d.getUTCDate();}, + getHours: function(d) {return d.getUTCHours();}, + getMinutes: function(d) {return d.getUTCMinutes();}, + getSeconds: function(d) {return d.getUTCSeconds();}, + getMilliseconds: function(d) {return d.getUTCMilliseconds();}, + getDay: function(d) {return d.getUTCDay();}, + makeDate: function(y, m, d, hh, mm, ss, ms) { + return new Date(Date.UTC(y, m, d, hh, mm, ss, ms)); + } +}; + +/** * Return a string version of the hours, minutes and seconds portion of a date. * @param {number} hh The hours (from 0-23) * @param {number} mm The minutes (from 0-59) @@ -494,31 +532,22 @@ Dygraph.hmsString_ = function(hh, mm, ss) { /** * Convert a JS date (millis since epoch) to a formatted string. - * @param {number} date The JavaScript date (ms since epoch) + * @param {number} time The JavaScript time value (ms since epoch) * @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, utc) { +Dygraph.dateString_ = function(time, utc) { var zeropad = Dygraph.zeropad; - 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(); - } + var accessors = utc ? Dygraph.DateAccessorsUTC : Dygraph.DateAccessorsLocal; + var date = new Date(time); + var y = accessors.getFullYear(date); + var m = accessors.getMonth(date); + var d = accessors.getDate(date); + var hh = accessors.getHours(date); + var mm = accessors.getMinutes(date); + var ss = accessors.getSeconds(date); // Get a year string: var year = "" + y; // Get a 0 padded month string @@ -528,7 +557,7 @@ Dygraph.dateString_ = function(date, utc) { var frac = hh * 3600 + mm * 60 + ss; var ret = year + "/" + month + "/" + day; if (frac) { - ret += " " + Dygraph.hmsString_(hh,mm,ss); + ret += " " + Dygraph.hmsString_(hh, mm, ss); } return ret; }; -- 2.7.4