Cihad Turhan
Cihad Turhan

Reputation: 2849

How to define custom time interval in d3.js

I'm trying to code an interval round function using the d3.js time intervals API.

The thing I want to do is fairly simple: write a function that rounds a time to the nearest 6 hours and returns it as a Date object.

For example:

It must not be so difficult, but d3.js api lacks of usage demos in API.

Upvotes: 7

Views: 7654

Answers (3)

Logan
Logan

Reputation: 165

Here's my solution which makes use of built-in d3 functions:

function another6HourRound(date) {
    var subHalf = d3.time.hour.offset(date, -3);
    var addHalf = d3.time.hour.offset(date, 3);
    return d3.time.hours(subHalf, addHalf, 6)[0];
}

Returns the nearest 6 hour interval (on 00, 06, 12, or 18)

Upvotes: 4

Cihad Turhan
Cihad Turhan

Reputation: 2849

Well, I've implemented my own solution. By diving into the source code of D3, I found how they write their time functions. For hour it's like:

  d3_time.hour = d3_time_interval(function(date) {
    var timezone = date.getTimezoneOffset() / 60;
    return new d3_date((Math.floor(date / 36e5 - timezone) + timezone) * 36e5);
  }, function(date, offset) {
    date.setTime(date.getTime() + Math.floor(offset) * 36e5);
  }, function(date) {
    return date.getHours();
  });
  d3_time.hours = d3_time.hour.range;
  d3_time.hours.utc = d3_time.hour.utc.range;

and I simply write

my6HourRound = function(date) {
    var hours = 6;
    var timezone = date.getTimezoneOffset() / 60;
    return new Date((Math.floor(date / 36e5 / hours - timezone) + timezone) * 36e5 * hours);
}

which works. I'm pretty sure there's a better method which makes this generic using D3 functions. Otherwise, you need to define custom functions for day, month, week, year etc. Therefore I'm not accepting my own question.

I'm looking forward to the one which make it in D3 way.

Upvotes: 2

musically_ut
musically_ut

Reputation: 34288

You are looking for this example: http://bl.ocks.org/mbostock/4149176

Working example for your case: http://bl.ocks.org/musically-ut/7699650

Code from example

function timeFormat(formats) {
  return function(date) {
    var i = formats.length - 1, f = formats[i];
    while (!f[1](date)) f = formats[--i];
    return d3.functor(f[0])(date);
  };
}

var customTimeFormat = timeFormat([
  [d3.time.format("%Y"), function() { return true; }],
  [d3.time.format("%B"), function(d) { return d.getMonth(); }],
  [d3.time.format("%b %d"), function(d) { return d.getDate() != 1; }],
  [d3.time.format("%a %d"), function(d) { return d.getDay() && d.getDate() != 1; }],
  [d3.time.format("%I %p"), function(d) { return d.getHours(); }],
  [d3.time.format("%I:%M"), function(d) { return d.getMinutes(); }],
  [d3.time.format(":%S"), function(d) { return d.getSeconds(); }],
  [d3.time.format(".%L"), function(d) { return d.getMilliseconds(); }]
]);

var xAxis = d3.svg.axis()
    .scale(x) // x is a scale.
    .tickFormat(customTimeFormat);

In your case, you want something of this kind:

var customTimeFormat = timeFormat([
  ["00:00", function () { return true; }],
  ["06:00", function (d) { return 3 <= d.getHours() && d.getHours() < 9; }],
  ["12:00", function (d) { return 9 <= d.getHours() && d.getHours() < 15; }],
  ["18:00", function (d) { return 15 <= d.getHours() && d.getHours() < 21; }]
]);

Upvotes: 2

Related Questions