Move date accessors to utils script and adapt tick generation and format.
authorJoan Pau Beltran <joanpau.beltran@socib.cat>
Mon, 3 Nov 2014 15:45:33 +0000 (16:45 +0100)
committerJoan Pau Beltran <joanpau.beltran@socib.cat>
Tue, 4 Nov 2014 13:57:56 +0000 (14:57 +0100)
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
dygraph-utils.js

index 7b3dae1..8818466 100644 (file)
@@ -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;
index 14aac18..9e74c7d 100644 (file)
@@ -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;
 };