You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
136 lines
4.5 KiB
136 lines
4.5 KiB
5 years ago
|
import {bisector, tickStep} from "d3-array";
|
||
|
import {interpolateNumber as reinterpolate} from "d3-interpolate";
|
||
|
import {timeYear, timeMonth, timeWeek, timeDay, timeHour, timeMinute, timeSecond, timeMillisecond} from "d3-time";
|
||
|
import {timeFormat} from "d3-time-format";
|
||
|
import {map} from "./array";
|
||
|
import {default as continuous, copy, deinterpolateLinear as deinterpolate} from "./continuous";
|
||
|
import nice from "./nice";
|
||
|
|
||
|
var durationSecond = 1000,
|
||
|
durationMinute = durationSecond * 60,
|
||
|
durationHour = durationMinute * 60,
|
||
|
durationDay = durationHour * 24,
|
||
|
durationWeek = durationDay * 7,
|
||
|
durationMonth = durationDay * 30,
|
||
|
durationYear = durationDay * 365;
|
||
|
|
||
|
function date(t) {
|
||
|
return new Date(t);
|
||
|
}
|
||
|
|
||
|
function number(t) {
|
||
|
return t instanceof Date ? +t : +new Date(+t);
|
||
|
}
|
||
|
|
||
|
export function calendar(year, month, week, day, hour, minute, second, millisecond, format) {
|
||
|
var scale = continuous(deinterpolate, reinterpolate),
|
||
|
invert = scale.invert,
|
||
|
domain = scale.domain;
|
||
|
|
||
|
var formatMillisecond = format(".%L"),
|
||
|
formatSecond = format(":%S"),
|
||
|
formatMinute = format("%I:%M"),
|
||
|
formatHour = format("%I %p"),
|
||
|
formatDay = format("%a %d"),
|
||
|
formatWeek = format("%b %d"),
|
||
|
formatMonth = format("%B"),
|
||
|
formatYear = format("%Y");
|
||
|
|
||
|
var tickIntervals = [
|
||
|
[second, 1, durationSecond],
|
||
|
[second, 5, 5 * durationSecond],
|
||
|
[second, 15, 15 * durationSecond],
|
||
|
[second, 30, 30 * durationSecond],
|
||
|
[minute, 1, durationMinute],
|
||
|
[minute, 5, 5 * durationMinute],
|
||
|
[minute, 15, 15 * durationMinute],
|
||
|
[minute, 30, 30 * durationMinute],
|
||
|
[ hour, 1, durationHour ],
|
||
|
[ hour, 3, 3 * durationHour ],
|
||
|
[ hour, 6, 6 * durationHour ],
|
||
|
[ hour, 12, 12 * durationHour ],
|
||
|
[ day, 1, durationDay ],
|
||
|
[ day, 2, 2 * durationDay ],
|
||
|
[ week, 1, durationWeek ],
|
||
|
[ month, 1, durationMonth ],
|
||
|
[ month, 3, 3 * durationMonth ],
|
||
|
[ year, 1, durationYear ]
|
||
|
];
|
||
|
|
||
|
function tickFormat(date) {
|
||
|
return (second(date) < date ? formatMillisecond
|
||
|
: minute(date) < date ? formatSecond
|
||
|
: hour(date) < date ? formatMinute
|
||
|
: day(date) < date ? formatHour
|
||
|
: month(date) < date ? (week(date) < date ? formatDay : formatWeek)
|
||
|
: year(date) < date ? formatMonth
|
||
|
: formatYear)(date);
|
||
|
}
|
||
|
|
||
|
function tickInterval(interval, start, stop, step) {
|
||
|
if (interval == null) interval = 10;
|
||
|
|
||
|
// If a desired tick count is specified, pick a reasonable tick interval
|
||
|
// based on the extent of the domain and a rough estimate of tick size.
|
||
|
// Otherwise, assume interval is already a time interval and use it.
|
||
|
if (typeof interval === "number") {
|
||
|
var target = Math.abs(stop - start) / interval,
|
||
|
i = bisector(function(i) { return i[2]; }).right(tickIntervals, target);
|
||
|
if (i === tickIntervals.length) {
|
||
|
step = tickStep(start / durationYear, stop / durationYear, interval);
|
||
|
interval = year;
|
||
|
} else if (i) {
|
||
|
i = tickIntervals[target / tickIntervals[i - 1][2] < tickIntervals[i][2] / target ? i - 1 : i];
|
||
|
step = i[1];
|
||
|
interval = i[0];
|
||
|
} else {
|
||
|
step = Math.max(tickStep(start, stop, interval), 1);
|
||
|
interval = millisecond;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return step == null ? interval : interval.every(step);
|
||
|
}
|
||
|
|
||
|
scale.invert = function(y) {
|
||
|
return new Date(invert(y));
|
||
|
};
|
||
|
|
||
|
scale.domain = function(_) {
|
||
|
return arguments.length ? domain(map.call(_, number)) : domain().map(date);
|
||
|
};
|
||
|
|
||
|
scale.ticks = function(interval, step) {
|
||
|
var d = domain(),
|
||
|
t0 = d[0],
|
||
|
t1 = d[d.length - 1],
|
||
|
r = t1 < t0,
|
||
|
t;
|
||
|
if (r) t = t0, t0 = t1, t1 = t;
|
||
|
t = tickInterval(interval, t0, t1, step);
|
||
|
t = t ? t.range(t0, t1 + 1) : []; // inclusive stop
|
||
|
return r ? t.reverse() : t;
|
||
|
};
|
||
|
|
||
|
scale.tickFormat = function(count, specifier) {
|
||
|
return specifier == null ? tickFormat : format(specifier);
|
||
|
};
|
||
|
|
||
|
scale.nice = function(interval, step) {
|
||
|
var d = domain();
|
||
|
return (interval = tickInterval(interval, d[0], d[d.length - 1], step))
|
||
|
? domain(nice(d, interval))
|
||
|
: scale;
|
||
|
};
|
||
|
|
||
|
scale.copy = function() {
|
||
|
return copy(scale, calendar(year, month, week, day, hour, minute, second, millisecond, format));
|
||
|
};
|
||
|
|
||
|
return scale;
|
||
|
}
|
||
|
|
||
|
export default function() {
|
||
|
return calendar(timeYear, timeMonth, timeWeek, timeDay, timeHour, timeMinute, timeSecond, timeMillisecond, timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]);
|
||
|
}
|