Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom multi-scale time formats in d3

Tags:

d3.js

d3.time.scale has a neat time formatter which uses multi-scale time formats. Is there an API or other way (yet) to specify a multi-scale time formats?

I know it is possible to create a new d3.time.format, but that won't be multi-scale.

Thanks.

like image 600
Ross Avatar asked Dec 12 '22 23:12

Ross


2 Answers

The multi-scale time format isn’t exposed as a public API outside of the standard one returned by a d3.time.scale’s tickFormat method.

That said, the implementation itself is fairly simple, so you could create your own multi-scale time format without a lot of work. The multi-scale time format is simply an ordered array of time formats, each of which has an associated test function. The first test function that returns true determines which time format is used.

The time format used by d3.time.scale has the following formats (taken from time/scale.js), specified in reverse order:

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

So, for example, if the time has a non-zero milliseconds field, then the ".%L" format is used; otherwise, if it has a non-zero seconds field, then ":%S" is used; and so on.

like image 56
mbostock Avatar answered Jan 18 '23 22:01

mbostock


In d3 version 4, d3.time.format has changed. Here is a new version of creating a conditional time formatter:

https://github.com/d3/d3-time-format#d3-time-format

var formatMillisecond = d3.timeFormat(".%L"),
    formatSecond = d3.timeFormat(":%S"),
    formatMinute = d3.timeFormat("%I:%M"),
    formatHour = d3.timeFormat("%I %p"),
    formatDay = d3.timeFormat("%a %d"),
    formatWeek = d3.timeFormat("%b %d"),
    formatMonth = d3.timeFormat("%B"),
    formatYear = d3.timeFormat("%Y");

function multiFormat(date) {
  return (d3.timeSecond(date) < date ? formatMillisecond
      : d3.timeMinute(date) < date ? formatSecond
      : d3.timeHour(date) < date ? formatMinute
      : d3.timeDay(date) < date ? formatHour
      : d3.timeMonth(date) < date ? (d3.timeWeek(date) < date ? formatDay : formatWeek)
      : d3.timeYear(date) < date ? formatMonth
      : formatYear)(date);
}
like image 22
Jeff Avatar answered Jan 18 '23 23:01

Jeff