html5 boiler plate
[scannr.git] / js / flotr2 / js / Date.js
blob:a/js/flotr2/js/Date.js -> blob:b/js/flotr2/js/Date.js
  /**
  * Flotr Date
  */
  Flotr.Date = {
   
  set : function (date, name, mode, value) {
  mode = mode || 'UTC';
  name = 'set' + (mode === 'UTC' ? 'UTC' : '') + name;
  date[name](value);
  },
   
  get : function (date, name, mode) {
  mode = mode || 'UTC';
  name = 'get' + (mode === 'UTC' ? 'UTC' : '') + name;
  return date[name]();
  },
   
  format: function(d, format, mode) {
  if (!d) return;
   
  // We should maybe use an "official" date format spec, like PHP date() or ColdFusion
  // http://fr.php.net/manual/en/function.date.php
  // http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=functions_c-d_29.html
  var
  get = this.get,
  tokens = {
  h: get(d, 'Hours', mode).toString(),
  H: leftPad(get(d, 'Hours', mode)),
  M: leftPad(get(d, 'Minutes', mode)),
  S: leftPad(get(d, 'Seconds', mode)),
  s: get(d, 'Milliseconds', mode),
  d: get(d, 'Date', mode).toString(),
  m: (get(d, 'Month', mode) + 1).toString(),
  y: get(d, 'FullYear', mode).toString(),
  b: Flotr.Date.monthNames[get(d, 'Month', mode)]
  };
   
  function leftPad(n){
  n += '';
  return n.length == 1 ? "0" + n : n;
  }
   
  var r = [], c,
  escape = false;
   
  for (var i = 0; i < format.length; ++i) {
  c = format.charAt(i);
   
  if (escape) {
  r.push(tokens[c] || c);
  escape = false;
  }
  else if (c == "%")
  escape = true;
  else
  r.push(c);
  }
  return r.join('');
  },
  getFormat: function(time, span) {
  var tu = Flotr.Date.timeUnits;
  if (time < tu.second) return "%h:%M:%S.%s";
  else if (time < tu.minute) return "%h:%M:%S";
  else if (time < tu.day) return (span < 2 * tu.day) ? "%h:%M" : "%b %d %h:%M";
  else if (time < tu.month) return "%b %d";
  else if (time < tu.year) return (span < tu.year) ? "%b" : "%b %y";
  else return "%y";
  },
  formatter: function (v, axis) {
  var
  options = axis.options,
  scale = Flotr.Date.timeUnits[options.timeUnit],
  d = new Date(v * scale);
   
  // first check global format
  if (axis.options.timeFormat)
  return Flotr.Date.format(d, options.timeFormat, options.timeMode);
   
  var span = (axis.max - axis.min) * scale,
  t = axis.tickSize * Flotr.Date.timeUnits[axis.tickUnit];
   
  return Flotr.Date.format(d, Flotr.Date.getFormat(t, span), options.timeMode);
  },
  generator: function(axis) {
   
  var
  set = this.set,
  get = this.get,
  timeUnits = this.timeUnits,
  spec = this.spec,
  options = axis.options,
  mode = options.timeMode,
  scale = timeUnits[options.timeUnit],
  min = axis.min * scale,
  max = axis.max * scale,
  delta = (max - min) / options.noTicks,
  ticks = [],
  tickSize = axis.tickSize,
  tickUnit,
  formatter, i;
   
  // Use custom formatter or time tick formatter
  formatter = (options.tickFormatter === Flotr.defaultTickFormatter ?
  this.formatter : options.tickFormatter
  );
   
  for (i = 0; i < spec.length - 1; ++i) {
  var d = spec[i][0] * timeUnits[spec[i][1]];
  if (delta < (d + spec[i+1][0] * timeUnits[spec[i+1][1]]) / 2 && d >= tickSize)
  break;
  }
  tickSize = spec[i][0];
  tickUnit = spec[i][1];
   
  // special-case the possibility of several years
  if (tickUnit == "year") {
  tickSize = Flotr.getTickSize(options.noTicks*timeUnits.year, min, max, 0);
   
  // Fix for 0.5 year case
  if (tickSize == 0.5) {
  tickUnit = "month";
  tickSize = 6;
  }
  }
   
  axis.tickUnit = tickUnit;
  axis.tickSize = tickSize;
   
  var step = tickSize * timeUnits[tickUnit];
  d = new Date(min);
   
  function setTick (name) {
  set(d, name, mode, Flotr.floorInBase(
  get(d, name, mode), tickSize
  ));
  }
   
  switch (tickUnit) {
  case "millisecond": setTick('Milliseconds'); break;
  case "second": setTick('Seconds'); break;
  case "minute": setTick('Minutes'); break;
  case "hour": setTick('Hours'); break;
  case "month": setTick('Month'); break;
  case "year": setTick('FullYear'); break;
  }
   
  // reset smaller components
  if (step >= timeUnits.second) set(d, 'Milliseconds', mode, 0);
  if (step >= timeUnits.minute) set(d, 'Seconds', mode, 0);
  if (step >= timeUnits.hour) set(d, 'Minutes', mode, 0);
  if (step >= timeUnits.day) set(d, 'Hours', mode, 0);
  if (step >= timeUnits.day * 4) set(d, 'Date', mode, 1);
  if (step >= timeUnits.year) set(d, 'Month', mode, 0);
   
  var carry = 0, v = NaN, prev;
  do {
  prev = v;
  v = d.getTime();
  ticks.push({ v: v / scale, label: formatter(v / scale, axis) });
  if (tickUnit == "month") {
  if (tickSize < 1) {
  /* a bit complicated - we'll divide the month up but we need to take care of fractions
  so we don't end up in the middle of a day */
  set(d, 'Date', mode, 1);
  var start = d.getTime();
  set(d, 'Month', mode, get(d, 'Month', mode) + 1);
  var end = d.getTime();
  d.setTime(v + carry * timeUnits.hour + (end - start) * tickSize);
  carry = get(d, 'Hours', mode);
  set(d, 'Hours', mode, 0);
  }
  else
  set(d, 'Month', mode, get(d, 'Month', mode) + tickSize);
  }
  else if (tickUnit == "year") {
  set(d, 'FullYear', mode, get(d, 'FullYear', mode) + tickSize);
  }
  else
  d.setTime(v + step);
   
  } while (v < max && v != prev);
   
  return ticks;
  },
  timeUnits: {
  millisecond: 1,
  second: 1000,
  minute: 1000 * 60,
  hour: 1000 * 60 * 60,
  day: 1000 * 60 * 60 * 24,
  month: 1000 * 60 * 60 * 24 * 30,
  year: 1000 * 60 * 60 * 24 * 365.2425
  },
  // the allowed tick sizes, after 1 year we use an integer algorithm
  spec: [
  [1, "millisecond"], [20, "millisecond"], [50, "millisecond"], [100, "millisecond"], [200, "millisecond"], [500, "millisecond"],
  [1, "second"], [2, "second"], [5, "second"], [10, "second"], [30, "second"],
  [1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"], [30, "minute"],
  [1, "hour"], [2, "hour"], [4, "hour"], [8, "hour"], [12, "hour"],
  [1, "day"], [2, "day"], [3, "day"],
  [0.25, "month"], [0.5, "month"], [1, "month"], [2, "month"], [3, "month"], [6, "month"],
  [1, "year"]
  ],
  monthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
  };