/** A named interval. */ export type LiteralTimeInterval = | "3 months" | "10 years" | TimeIntervalName | (`${TimeIntervalName}s` & Record) | (`${number} ${TimeIntervalName}` & Record) | (`${number} ${TimeIntervalName}s` & Record); /** * The built-in time intervals; UTC or local time, depending on context. The * *week* interval is an alias for *sunday*. The *quarter* interval is every * three months, and the *half* interval is every six months, aligned at the * start of the year. */ export type TimeIntervalName = | "second" | "minute" | "hour" | "day" | "week" | "month" | "quarter" // 3 months | "half" // 6 months | "year" | "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday" | "sunday"; /** A custom interval implementation. */ export interface IntervalImplementation { /** * Returns the value representing the greatest interval boundary less than or * equal to the specified *value*. For example, day.floor(*date*) typically * returns 12:00 AM on the given date. * * This method is idempotent: if the specified value is already floored to the * current interval, the same value is returned. Furthermore, the returned * value is the minimum expressible value of the associated interval, such * that floor(floor(*value*) - *epsilon*) returns the preceding interval * boundary value. */ floor(value: T): T; /** * Returns a new value equal to *value* plus *step* intervals. If *step* is * not specified it defaults to 1. If *step* is negative, then the returned * value will be less than the specified *value*; if *step* is zero, then the * same *value* is returned; if *step* is not an integer, it is floored. * * This method does not round the specified *value* to the interval. For * example, if *date* is today at 5:34 PM, then day.offset(*date*, 1) returns * 5:34 PM tomorrow. */ offset(value: T, step?: number): T; } /** * A custom interval implementation that also supports the range method, say for * generating thresholds or ticks. */ export interface RangeIntervalImplementation extends IntervalImplementation { /** * Returns an array of values representing every interval boundary greater * than or equal to *start* (inclusive) and less than *stop* (exclusive). The * first value in the returned array is the least boundary greater than or * equal to *start*; subsequent values are offset by intervals and floored. */ range(start: T, stop: T): T[]; } /** * A custom interval implementation that also supports the range and ceil * methods, used for nicing scale domains. */ export interface NiceIntervalImplementation extends RangeIntervalImplementation { /** * Returns the value representing the least interval boundary value greater * than or equal to the specified *value*. For example, day.ceil(*date*) * typically returns 12:00 AM on the date following the given date. * * This method is idempotent: if the specified date is already ceilinged to * the current interval, the same value is returned. Furthermore, the returned * value is the maximum expressible value of the associated interval, such * that ceil(ceil(*value*) + *epsilon*) returns the following interval * boundary value. */ ceil(value: T): T; } /** A literal that can be automatically promoted to an interval. */ type LiteralInterval = T extends Date ? LiteralTimeInterval : T extends number ? number : never; /** * How to partition a continuous range into discrete intervals; one of: * * - an object that implements *floor* and *offset* methods * - a named time interval such as *day* (for date intervals) * - a number (for number intervals), defining intervals at integer multiples of *n* */ export type Interval = LiteralInterval | IntervalImplementation; /** * An interval that also supports the *range* method, used to subdivide a * continuous range into discrete partitions, say for thresholds or ticks; one * of: * * - an object that implements *floor*, *offset*, and *range* methods * - a named time interval such as *day* (for date intervals) * - a number (for number intervals), defining intervals at integer multiples of *n* */ export type RangeInterval = LiteralInterval | RangeIntervalImplementation; /** * A range interval that also supports the *ceil* method, used to nice a scale * domain; one of: * * - an object that implements *floor*, *ceil*, *offset*, and *range* methods * - a named time interval such as *day* (for date intervals) * - a number (for number intervals), defining intervals at integer multiples of *n* */ export type NiceInterval = LiteralInterval | NiceIntervalImplementation; /** * Given a number *period*, returns a corresponding numeric range interval. If * *period* is a negative number, the returned interval uses 1 / -*period*, * allowing greater precision when *period* is a negative integer. */ export function numberInterval(period: number): RangeIntervalImplementation; /** Given a string *period*, returns a corresponding local time nice interval. */ export function timeInterval(period: LiteralTimeInterval): NiceIntervalImplementation; /** Given a string *period*, returns a corresponding UTC nice interval. */ export function utcInterval(period: LiteralTimeInterval): NiceIntervalImplementation;