diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts
index 5aaf69e194..351b8e372d 100644
--- a/docs/.vitepress/config.ts
+++ b/docs/.vitepress/config.ts
@@ -68,6 +68,7 @@ export default defineConfig({
{text: "Legends", link: "/features/legends"},
{text: "Curves", link: "/features/curves"},
{text: "Formats", link: "/features/formats"},
+ {text: "Intervals", link: "/features/intervals"},
{text: "Markers", link: "/features/markers"},
{text: "Shorthand", link: "/features/shorthand"},
{text: "Accessibility", link: "/features/accessibility"}
diff --git a/docs/data/api.data.ts b/docs/data/api.data.ts
index 3efbb7c156..bbabdd8cce 100644
--- a/docs/data/api.data.ts
+++ b/docs/data/api.data.ts
@@ -43,6 +43,7 @@ function getHref(name: string, path: string): string {
switch (path) {
case "features/curve":
case "features/format":
+ case "features/interval":
case "features/mark":
case "features/marker":
case "features/plot":
diff --git a/docs/features/intervals.md b/docs/features/intervals.md
new file mode 100644
index 0000000000..835c8d7c22
--- /dev/null
+++ b/docs/features/intervals.md
@@ -0,0 +1,61 @@
+
+
+# Intervals
+
+Plot provides several built-in interval implementations for use with the **tick** option for [scales](./scales.md), as the **thresholds** option for a [bin transform](../transforms/bin.md), or other use. See also [d3-time](https://d3js.org/d3-time). You can also implement custom intervals.
+
+At a minimum, intervals implement *interval*.**floor** and *interval*.**offset**. Range intervals additionally implement *interval*.**range**, and nice intervals additionally implement *interval*.**ceil**. These latter implementations are required in some contexts; see Plot’s TypeScript definitions for details.
+
+The *interval*.**floor** method takes a *value* and returns the corresponding value representing the greatest interval boundary less than or equal to the specified *value*. For example, for the “day” time interval, it returns the preceding midnight:
+
+```js
+Plot.utcInterval("day").floor(new Date("2013-04-12T12:34:56Z")) // 2013-04-12
+```
+
+The *interval*.**offset** method takes a *value* and returns the corresponding 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*. For example:
+
+```js
+Plot.utcInterval("day").offset(new Date("2013-04-12T12:34:56Z"), 1) // 2013-04-13T12:34:56Z
+Plot.utcInterval("day").offset(new Date("2013-04-12T12:34:56Z"), -2) // 2013-03-22T12:34:56Z
+```
+
+The *interval*.**range** method 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.
+
+```js
+Plot.utcInterval("week").range(new Date("2013-04-12T12:34:56Z"), new Date("2013-05-12T12:34:56Z")) // [2013-04-14, 2013-04-21, 2013-04-28, 2013-05-05, 2013-05-12]
+```
+
+The *interval*.**ceil** method returns the value representing the least interval boundary value greater than or equal to the specified *value*. For example, for the “day” time interval, it returns the preceding midnight:
+
+```js
+Plot.utcInterval("day").ceil(new Date("2013-04-12T12:34:56Z")) // 2013-04-13
+```
+
+## numberInterval(*period*) {#numberInterval}
+
+```js
+Plot.numberInterval(2)
+```
+
+Given a number *period*, returns a corresponding range interval implementation. If *period* is a negative number, the resulting interval uses 1 / -*period*; this allows more precise results when *period* is a negative integer. The returned interval implements the *interval*.range, *interval*.floor, and *interval*.offset methods.
+
+## timeInterval(*period*) {#timeInterval}
+
+```js
+Plot.timeInterval("2 days")
+```
+
+Given a string *period* describing a local time interval, returns a corresponding nice interval implementation. The period can be *second*, *minute*, *hour*, *day*, *week*, *month*, *quarter*, *half*, *year*, *monday*, *tuesday*, *wednesday*, *thursday*, *friday*, *saturday*, or *sunday*, or a skip interval consisting of a number followed by the interval name (possibly pluralized), such as *3 months* or *10 years*. The returned interval implements the *interval*.range, *interval*.floor, *interval*.ceil, and *interval*.offset methods.
+
+## utcInterval(*period*) {#utcInterval}
+
+```js
+Plot.utcInterval("2 days")
+```
+
+Given a string *period* describing a UTC time interval, returns a corresponding nice interval implementation. The period can be *second*, *minute*, *hour*, *day*, *week*, *month*, *quarter*, *half*, *year*, *monday*, *tuesday*, *wednesday*, *thursday*, *friday*, *saturday*, or *sunday*, or a skip interval consisting of a number followed by the interval name (possibly pluralized), such as *3 months* or *10 years*. The returned interval implements the *interval*.range, *interval*.floor, *interval*.ceil, and *interval*.offset methods.
diff --git a/src/index.js b/src/index.js
index c3a87668ae..df33d998d4 100644
--- a/src/index.js
+++ b/src/index.js
@@ -56,3 +56,5 @@ export {pointer, pointerX, pointerY} from "./interactions/pointer.js";
export {formatIsoDate, formatNumber, formatWeekday, formatMonth} from "./format.js";
export {scale} from "./scales.js";
export {legend} from "./legends.js";
+export {numberInterval} from "./options.js";
+export {timeInterval, utcInterval} from "./time.js";
diff --git a/src/interval.d.ts b/src/interval.d.ts
index 29882a04ff..2c76a015a4 100644
--- a/src/interval.d.ts
+++ b/src/interval.d.ts
@@ -1,4 +1,4 @@
-// For internal use.
+/** A named interval. */
export type LiteralTimeInterval =
| "3 months"
| "10 years"
@@ -124,3 +124,16 @@ export type RangeInterval = LiteralInterval | RangeIntervalImplement
* - 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;
diff --git a/src/options.js b/src/options.js
index 387daa94fb..a170e4c003 100644
--- a/src/options.js
+++ b/src/options.js
@@ -1,7 +1,7 @@
import {quantile, range as rangei} from "d3";
import {parse as isoParse} from "isoformat";
import {defined} from "./defined.js";
-import {maybeTimeInterval, maybeUtcInterval} from "./time.js";
+import {timeInterval, utcInterval} from "./time.js";
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray
export const TypedArray = Object.getPrototypeOf(Uint8Array);
@@ -322,27 +322,30 @@ export function maybeIntervalTransform(interval, type) {
// range} object similar to a D3 time interval.
export function maybeInterval(interval, type) {
if (interval == null) return;
- if (typeof interval === "number") {
- if (0 < interval && interval < 1 && Number.isInteger(1 / interval)) interval = -1 / interval;
- const n = Math.abs(interval);
- return interval < 0
- ? {
- floor: (d) => Math.floor(d * n) / n,
- offset: (d) => (d * n + 1) / n, // note: no optional step for simplicity
- range: (lo, hi) => rangei(Math.ceil(lo * n), hi * n).map((x) => x / n)
- }
- : {
- floor: (d) => Math.floor(d / n) * n,
- offset: (d) => d + n, // note: no optional step for simplicity
- range: (lo, hi) => rangei(Math.ceil(lo / n), hi / n).map((x) => x * n)
- };
- }
- if (typeof interval === "string") return (type === "time" ? maybeTimeInterval : maybeUtcInterval)(interval);
+ if (typeof interval === "number") return numberInterval(interval);
+ if (typeof interval === "string") return (type === "time" ? timeInterval : utcInterval)(interval);
if (typeof interval.floor !== "function") throw new Error("invalid interval; missing floor method");
if (typeof interval.offset !== "function") throw new Error("invalid interval; missing offset method");
return interval;
}
+export function numberInterval(interval) {
+ interval = +interval;
+ if (0 < interval && interval < 1 && Number.isInteger(1 / interval)) interval = -1 / interval;
+ const n = Math.abs(interval);
+ return interval < 0
+ ? {
+ floor: (d) => Math.floor(d * n) / n,
+ offset: (d, s = 1) => (d * n + Math.floor(s)) / n,
+ range: (lo, hi) => rangei(Math.ceil(lo * n), hi * n).map((x) => x / n)
+ }
+ : {
+ floor: (d) => Math.floor(d / n) * n,
+ offset: (d, s = 1) => d + n * Math.floor(s),
+ range: (lo, hi) => rangei(Math.ceil(lo / n), hi / n).map((x) => x * n)
+ };
+}
+
// Like maybeInterval, but requires a range method too.
export function maybeRangeInterval(interval, type) {
interval = maybeInterval(interval, type);
diff --git a/src/time.js b/src/time.js
index 63722f587c..118c99daad 100644
--- a/src/time.js
+++ b/src/time.js
@@ -183,11 +183,11 @@ export function parseTimeInterval(input) {
return [name, period];
}
-export function maybeTimeInterval(input) {
+export function timeInterval(input) {
return asInterval(parseTimeInterval(input), "time");
}
-export function maybeUtcInterval(input) {
+export function utcInterval(input) {
return asInterval(parseTimeInterval(input), "utc");
}
@@ -209,7 +209,7 @@ export function generalizeTimeInterval(interval, n) {
if (!tickIntervals.some(([, d]) => d === duration)) return; // nonstandard or unknown interval
if (duration % durationDay === 0 && durationDay < duration && duration < durationMonth) return; // not generalizable
const [i] = tickIntervals[bisector(([, step]) => Math.log(step)).center(tickIntervals, Math.log(duration * n))];
- return (interval[intervalType] === "time" ? maybeTimeInterval : maybeUtcInterval)(i);
+ return (interval[intervalType] === "time" ? timeInterval : utcInterval)(i);
}
function formatTimeInterval(name, type, anchor) {
diff --git a/src/transforms/bin.js b/src/transforms/bin.js
index 16abb9d883..02321a3345 100644
--- a/src/transforms/bin.js
+++ b/src/transforms/bin.js
@@ -28,7 +28,7 @@ import {
mid,
valueof
} from "../options.js";
-import {maybeUtcInterval} from "../time.js";
+import {utcInterval} from "../time.js";
import {basic} from "./basic.js";
import {
hasOutput,
@@ -322,7 +322,7 @@ export function maybeThresholds(thresholds, interval, defaultThresholds = thresh
case "auto":
return thresholdAuto;
}
- return maybeUtcInterval(thresholds);
+ return utcInterval(thresholds);
}
return thresholds; // pass array, count, or function to bin.thresholds
}
diff --git a/test/interval-test.js b/test/interval-test.js
new file mode 100644
index 0000000000..4f7fcefbf9
--- /dev/null
+++ b/test/interval-test.js
@@ -0,0 +1,64 @@
+import assert from "assert";
+import {numberInterval} from "../src/options.js";
+
+describe("numberInterval(interval)", () => {
+ it("coerces the given interval to a number", () => {
+ assert.deepStrictEqual(numberInterval("1").range(0, 10), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+ });
+ it("implements range", () => {
+ assert.deepStrictEqual(numberInterval(1).range(0, 10), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+ assert.deepStrictEqual(numberInterval(1).range(1, 9), [1, 2, 3, 4, 5, 6, 7, 8]);
+ assert.deepStrictEqual(numberInterval(2).range(1, 9), [2, 4, 6, 8]);
+ assert.deepStrictEqual(numberInterval(-1).range(2, 5), [2, 3, 4]);
+ assert.deepStrictEqual(numberInterval(-2).range(2, 5), [2, 2.5, 3, 3.5, 4, 4.5]);
+ assert.deepStrictEqual(numberInterval(2).range(0, 10), [0, 2, 4, 6, 8]);
+ assert.deepStrictEqual(numberInterval(-2).range(0, 5), [0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5]);
+ });
+ it("considers descending ranges to be empty", () => {
+ assert.deepStrictEqual(numberInterval(1).range(10, 0), []);
+ assert.deepStrictEqual(numberInterval(1).range(-1, -9), []);
+ });
+ it("considers invalid ranges to be empty", () => {
+ assert.deepStrictEqual(numberInterval(1).range(0, Infinity), []);
+ assert.deepStrictEqual(numberInterval(1).range(NaN, 0), []);
+ });
+ it("considers invalid intervals to be empty", () => {
+ assert.deepStrictEqual(numberInterval(NaN).range(0, 10), []);
+ assert.deepStrictEqual(numberInterval(-Infinity).range(0, 10), []);
+ assert.deepStrictEqual(numberInterval(0).range(0, 10), []);
+ });
+ it("implements floor", () => {
+ assert.strictEqual(numberInterval(1).floor(9.9), 9);
+ assert.strictEqual(numberInterval(2).floor(9), 8);
+ assert.strictEqual(numberInterval(-2).floor(8.6), 8.5);
+ });
+ it("implements offset", () => {
+ assert.strictEqual(numberInterval(1).offset(8), 9);
+ assert.strictEqual(numberInterval(2).offset(8), 10);
+ assert.strictEqual(numberInterval(-2).offset(8), 8.5);
+ });
+ it("implements offset with step", () => {
+ assert.strictEqual(numberInterval(1).offset(8, 2), 10);
+ assert.strictEqual(numberInterval(2).offset(8, 2), 12);
+ assert.strictEqual(numberInterval(-2).offset(8, 2), 9);
+ });
+ it("does not require an aligned offset", () => {
+ assert.strictEqual(numberInterval(2).offset(7), 9);
+ assert.strictEqual(numberInterval(-2).offset(7.1), 7.6);
+ });
+ it("floors the offset step", () => {
+ assert.strictEqual(numberInterval(1).offset(8, 2.5), 10);
+ assert.strictEqual(numberInterval(2).offset(8, 2.5), 12);
+ assert.strictEqual(numberInterval(-2).offset(8, 2.5), 9);
+ });
+ it("coerces the offset step", () => {
+ assert.strictEqual(numberInterval(1).offset(8, "2.5"), 10);
+ assert.strictEqual(numberInterval(2).offset(8, "2.5"), 12);
+ assert.strictEqual(numberInterval(-2).offset(8, "2.5"), 9);
+ });
+ it("allows a negative offset step", () => {
+ assert.strictEqual(numberInterval(1).offset(8, -2), 6);
+ assert.strictEqual(numberInterval(2).offset(8, -2), 4);
+ assert.strictEqual(numberInterval(-2).offset(8, -2), 7);
+ });
+});
diff --git a/test/marks/time-test.js b/test/marks/time-test.js
index 8445bcd820..250cb150df 100644
--- a/test/marks/time-test.js
+++ b/test/marks/time-test.js
@@ -1,155 +1,155 @@
import assert from "assert";
import * as d3 from "d3";
-import {maybeTimeInterval, maybeUtcInterval} from "../../src/time.js";
+import {timeInterval, utcInterval} from "../../src/time.js";
-it("maybeTimeInterval('period') returns the expected time interval", () => {
- assert.strictEqual(maybeTimeInterval("second"), d3.timeSecond);
- assert.strictEqual(maybeTimeInterval("minute"), d3.timeMinute);
- assert.strictEqual(maybeTimeInterval("hour"), d3.timeHour);
- assert.strictEqual(maybeTimeInterval("day"), d3.timeDay);
- assert.strictEqual(maybeTimeInterval("week"), d3.timeWeek);
- assert.strictEqual(maybeTimeInterval("month"), d3.timeMonth);
- assert.strictEqual(maybeTimeInterval("year"), d3.timeYear);
- assert.strictEqual(maybeTimeInterval("monday"), d3.timeMonday);
- assert.strictEqual(maybeTimeInterval("tuesday"), d3.timeTuesday);
- assert.strictEqual(maybeTimeInterval("wednesday"), d3.timeWednesday);
- assert.strictEqual(maybeTimeInterval("thursday"), d3.timeThursday);
- assert.strictEqual(maybeTimeInterval("friday"), d3.timeFriday);
- assert.strictEqual(maybeTimeInterval("saturday"), d3.timeSaturday);
- assert.strictEqual(maybeTimeInterval("sunday"), d3.timeSunday);
+it("timeInterval('period') returns the expected time interval", () => {
+ assert.strictEqual(timeInterval("second"), d3.timeSecond);
+ assert.strictEqual(timeInterval("minute"), d3.timeMinute);
+ assert.strictEqual(timeInterval("hour"), d3.timeHour);
+ assert.strictEqual(timeInterval("day"), d3.timeDay);
+ assert.strictEqual(timeInterval("week"), d3.timeWeek);
+ assert.strictEqual(timeInterval("month"), d3.timeMonth);
+ assert.strictEqual(timeInterval("year"), d3.timeYear);
+ assert.strictEqual(timeInterval("monday"), d3.timeMonday);
+ assert.strictEqual(timeInterval("tuesday"), d3.timeTuesday);
+ assert.strictEqual(timeInterval("wednesday"), d3.timeWednesday);
+ assert.strictEqual(timeInterval("thursday"), d3.timeThursday);
+ assert.strictEqual(timeInterval("friday"), d3.timeFriday);
+ assert.strictEqual(timeInterval("saturday"), d3.timeSaturday);
+ assert.strictEqual(timeInterval("sunday"), d3.timeSunday);
});
-it("maybeTimeInterval('periods') returns the expected time interval", () => {
- assert.strictEqual(maybeTimeInterval("seconds"), d3.timeSecond);
- assert.strictEqual(maybeTimeInterval("minutes"), d3.timeMinute);
- assert.strictEqual(maybeTimeInterval("hours"), d3.timeHour);
- assert.strictEqual(maybeTimeInterval("days"), d3.timeDay);
- assert.strictEqual(maybeTimeInterval("weeks"), d3.timeWeek);
- assert.strictEqual(maybeTimeInterval("months"), d3.timeMonth);
- assert.strictEqual(maybeTimeInterval("years"), d3.timeYear);
- assert.strictEqual(maybeTimeInterval("mondays"), d3.timeMonday);
- assert.strictEqual(maybeTimeInterval("tuesdays"), d3.timeTuesday);
- assert.strictEqual(maybeTimeInterval("wednesdays"), d3.timeWednesday);
- assert.strictEqual(maybeTimeInterval("thursdays"), d3.timeThursday);
- assert.strictEqual(maybeTimeInterval("fridays"), d3.timeFriday);
- assert.strictEqual(maybeTimeInterval("saturdays"), d3.timeSaturday);
- assert.strictEqual(maybeTimeInterval("sundays"), d3.timeSunday);
+it("timeInterval('periods') returns the expected time interval", () => {
+ assert.strictEqual(timeInterval("seconds"), d3.timeSecond);
+ assert.strictEqual(timeInterval("minutes"), d3.timeMinute);
+ assert.strictEqual(timeInterval("hours"), d3.timeHour);
+ assert.strictEqual(timeInterval("days"), d3.timeDay);
+ assert.strictEqual(timeInterval("weeks"), d3.timeWeek);
+ assert.strictEqual(timeInterval("months"), d3.timeMonth);
+ assert.strictEqual(timeInterval("years"), d3.timeYear);
+ assert.strictEqual(timeInterval("mondays"), d3.timeMonday);
+ assert.strictEqual(timeInterval("tuesdays"), d3.timeTuesday);
+ assert.strictEqual(timeInterval("wednesdays"), d3.timeWednesday);
+ assert.strictEqual(timeInterval("thursdays"), d3.timeThursday);
+ assert.strictEqual(timeInterval("fridays"), d3.timeFriday);
+ assert.strictEqual(timeInterval("saturdays"), d3.timeSaturday);
+ assert.strictEqual(timeInterval("sundays"), d3.timeSunday);
});
-it("maybeTimeInterval('1 periods) returns the expected time interval", () => {
- assert.strictEqual(maybeTimeInterval("1 second"), d3.timeSecond);
- assert.strictEqual(maybeTimeInterval("1 minute"), d3.timeMinute);
- assert.strictEqual(maybeTimeInterval("1 hour"), d3.timeHour);
- assert.strictEqual(maybeTimeInterval("1 day"), d3.timeDay);
- assert.strictEqual(maybeTimeInterval("1 week"), d3.timeWeek);
- assert.strictEqual(maybeTimeInterval("1 month"), d3.timeMonth);
- assert.strictEqual(maybeTimeInterval("1 year"), d3.timeYear);
- assert.strictEqual(maybeTimeInterval("1 monday"), d3.timeMonday);
- assert.strictEqual(maybeTimeInterval("1 tuesday"), d3.timeTuesday);
- assert.strictEqual(maybeTimeInterval("1 wednesday"), d3.timeWednesday);
- assert.strictEqual(maybeTimeInterval("1 thursday"), d3.timeThursday);
- assert.strictEqual(maybeTimeInterval("1 friday"), d3.timeFriday);
- assert.strictEqual(maybeTimeInterval("1 saturday"), d3.timeSaturday);
- assert.strictEqual(maybeTimeInterval("1 sunday"), d3.timeSunday);
+it("timeInterval('1 periods) returns the expected time interval", () => {
+ assert.strictEqual(timeInterval("1 second"), d3.timeSecond);
+ assert.strictEqual(timeInterval("1 minute"), d3.timeMinute);
+ assert.strictEqual(timeInterval("1 hour"), d3.timeHour);
+ assert.strictEqual(timeInterval("1 day"), d3.timeDay);
+ assert.strictEqual(timeInterval("1 week"), d3.timeWeek);
+ assert.strictEqual(timeInterval("1 month"), d3.timeMonth);
+ assert.strictEqual(timeInterval("1 year"), d3.timeYear);
+ assert.strictEqual(timeInterval("1 monday"), d3.timeMonday);
+ assert.strictEqual(timeInterval("1 tuesday"), d3.timeTuesday);
+ assert.strictEqual(timeInterval("1 wednesday"), d3.timeWednesday);
+ assert.strictEqual(timeInterval("1 thursday"), d3.timeThursday);
+ assert.strictEqual(timeInterval("1 friday"), d3.timeFriday);
+ assert.strictEqual(timeInterval("1 saturday"), d3.timeSaturday);
+ assert.strictEqual(timeInterval("1 sunday"), d3.timeSunday);
});
-it("maybeTimeInterval('1 periods') returns the expected time interval", () => {
- assert.strictEqual(maybeTimeInterval("1 seconds"), d3.timeSecond);
- assert.strictEqual(maybeTimeInterval("1 minutes"), d3.timeMinute);
- assert.strictEqual(maybeTimeInterval("1 hours"), d3.timeHour);
- assert.strictEqual(maybeTimeInterval("1 days"), d3.timeDay);
- assert.strictEqual(maybeTimeInterval("1 weeks"), d3.timeWeek);
- assert.strictEqual(maybeTimeInterval("1 months"), d3.timeMonth);
- assert.strictEqual(maybeTimeInterval("1 years"), d3.timeYear);
- assert.strictEqual(maybeTimeInterval("1 mondays"), d3.timeMonday);
- assert.strictEqual(maybeTimeInterval("1 tuesdays"), d3.timeTuesday);
- assert.strictEqual(maybeTimeInterval("1 wednesdays"), d3.timeWednesday);
- assert.strictEqual(maybeTimeInterval("1 thursdays"), d3.timeThursday);
- assert.strictEqual(maybeTimeInterval("1 fridays"), d3.timeFriday);
- assert.strictEqual(maybeTimeInterval("1 saturdays"), d3.timeSaturday);
- assert.strictEqual(maybeTimeInterval("1 sundays"), d3.timeSunday);
+it("timeInterval('1 periods') returns the expected time interval", () => {
+ assert.strictEqual(timeInterval("1 seconds"), d3.timeSecond);
+ assert.strictEqual(timeInterval("1 minutes"), d3.timeMinute);
+ assert.strictEqual(timeInterval("1 hours"), d3.timeHour);
+ assert.strictEqual(timeInterval("1 days"), d3.timeDay);
+ assert.strictEqual(timeInterval("1 weeks"), d3.timeWeek);
+ assert.strictEqual(timeInterval("1 months"), d3.timeMonth);
+ assert.strictEqual(timeInterval("1 years"), d3.timeYear);
+ assert.strictEqual(timeInterval("1 mondays"), d3.timeMonday);
+ assert.strictEqual(timeInterval("1 tuesdays"), d3.timeTuesday);
+ assert.strictEqual(timeInterval("1 wednesdays"), d3.timeWednesday);
+ assert.strictEqual(timeInterval("1 thursdays"), d3.timeThursday);
+ assert.strictEqual(timeInterval("1 fridays"), d3.timeFriday);
+ assert.strictEqual(timeInterval("1 saturdays"), d3.timeSaturday);
+ assert.strictEqual(timeInterval("1 sundays"), d3.timeSunday);
});
-it("maybeTimeInterval('n seconds') returns the expected time interval", () => {
+it("timeInterval('n seconds') returns the expected time interval", () => {
const start = new Date("2012-01-01T12:01:02");
const end = new Date("2012-01-01T12:14:08");
- assert.deepStrictEqual(maybeTimeInterval("5 seconds").range(start, end), d3.timeSecond.every(5).range(start, end));
- assert.deepStrictEqual(maybeTimeInterval("15 seconds").range(start, end), d3.timeSecond.every(15).range(start, end));
- assert.deepStrictEqual(maybeTimeInterval("45 seconds").range(start, end), d3.timeSecond.every(45).range(start, end));
+ assert.deepStrictEqual(timeInterval("5 seconds").range(start, end), d3.timeSecond.every(5).range(start, end));
+ assert.deepStrictEqual(timeInterval("15 seconds").range(start, end), d3.timeSecond.every(15).range(start, end));
+ assert.deepStrictEqual(timeInterval("45 seconds").range(start, end), d3.timeSecond.every(45).range(start, end));
});
-it("maybeUtcInterval('period') returns the expected UTC interval", () => {
- assert.strictEqual(maybeUtcInterval("second"), d3.utcSecond);
- assert.strictEqual(maybeUtcInterval("minute"), d3.utcMinute);
- assert.strictEqual(maybeUtcInterval("hour"), d3.utcHour);
- assert.strictEqual(maybeUtcInterval("day"), d3.unixDay);
- assert.strictEqual(maybeUtcInterval("week"), d3.utcWeek);
- assert.strictEqual(maybeUtcInterval("month"), d3.utcMonth);
- assert.strictEqual(maybeUtcInterval("year"), d3.utcYear);
- assert.strictEqual(maybeUtcInterval("monday"), d3.utcMonday);
- assert.strictEqual(maybeUtcInterval("tuesday"), d3.utcTuesday);
- assert.strictEqual(maybeUtcInterval("wednesday"), d3.utcWednesday);
- assert.strictEqual(maybeUtcInterval("thursday"), d3.utcThursday);
- assert.strictEqual(maybeUtcInterval("friday"), d3.utcFriday);
- assert.strictEqual(maybeUtcInterval("saturday"), d3.utcSaturday);
- assert.strictEqual(maybeUtcInterval("sunday"), d3.utcSunday);
+it("utcInterval('period') returns the expected UTC interval", () => {
+ assert.strictEqual(utcInterval("second"), d3.utcSecond);
+ assert.strictEqual(utcInterval("minute"), d3.utcMinute);
+ assert.strictEqual(utcInterval("hour"), d3.utcHour);
+ assert.strictEqual(utcInterval("day"), d3.unixDay);
+ assert.strictEqual(utcInterval("week"), d3.utcWeek);
+ assert.strictEqual(utcInterval("month"), d3.utcMonth);
+ assert.strictEqual(utcInterval("year"), d3.utcYear);
+ assert.strictEqual(utcInterval("monday"), d3.utcMonday);
+ assert.strictEqual(utcInterval("tuesday"), d3.utcTuesday);
+ assert.strictEqual(utcInterval("wednesday"), d3.utcWednesday);
+ assert.strictEqual(utcInterval("thursday"), d3.utcThursday);
+ assert.strictEqual(utcInterval("friday"), d3.utcFriday);
+ assert.strictEqual(utcInterval("saturday"), d3.utcSaturday);
+ assert.strictEqual(utcInterval("sunday"), d3.utcSunday);
});
-it("maybeUtcInterval('periods') returns the expected UTC interval", () => {
- assert.strictEqual(maybeUtcInterval("seconds"), d3.utcSecond);
- assert.strictEqual(maybeUtcInterval("minutes"), d3.utcMinute);
- assert.strictEqual(maybeUtcInterval("hours"), d3.utcHour);
- assert.strictEqual(maybeUtcInterval("days"), d3.unixDay);
- assert.strictEqual(maybeUtcInterval("weeks"), d3.utcWeek);
- assert.strictEqual(maybeUtcInterval("months"), d3.utcMonth);
- assert.strictEqual(maybeUtcInterval("years"), d3.utcYear);
- assert.strictEqual(maybeUtcInterval("mondays"), d3.utcMonday);
- assert.strictEqual(maybeUtcInterval("tuesdays"), d3.utcTuesday);
- assert.strictEqual(maybeUtcInterval("wednesdays"), d3.utcWednesday);
- assert.strictEqual(maybeUtcInterval("thursdays"), d3.utcThursday);
- assert.strictEqual(maybeUtcInterval("fridays"), d3.utcFriday);
- assert.strictEqual(maybeUtcInterval("saturdays"), d3.utcSaturday);
- assert.strictEqual(maybeUtcInterval("sundays"), d3.utcSunday);
+it("utcInterval('periods') returns the expected UTC interval", () => {
+ assert.strictEqual(utcInterval("seconds"), d3.utcSecond);
+ assert.strictEqual(utcInterval("minutes"), d3.utcMinute);
+ assert.strictEqual(utcInterval("hours"), d3.utcHour);
+ assert.strictEqual(utcInterval("days"), d3.unixDay);
+ assert.strictEqual(utcInterval("weeks"), d3.utcWeek);
+ assert.strictEqual(utcInterval("months"), d3.utcMonth);
+ assert.strictEqual(utcInterval("years"), d3.utcYear);
+ assert.strictEqual(utcInterval("mondays"), d3.utcMonday);
+ assert.strictEqual(utcInterval("tuesdays"), d3.utcTuesday);
+ assert.strictEqual(utcInterval("wednesdays"), d3.utcWednesday);
+ assert.strictEqual(utcInterval("thursdays"), d3.utcThursday);
+ assert.strictEqual(utcInterval("fridays"), d3.utcFriday);
+ assert.strictEqual(utcInterval("saturdays"), d3.utcSaturday);
+ assert.strictEqual(utcInterval("sundays"), d3.utcSunday);
});
-it("maybeUtcInterval('1 periods) returns the expected UTC interval", () => {
- assert.strictEqual(maybeUtcInterval("1 second"), d3.utcSecond);
- assert.strictEqual(maybeUtcInterval("1 minute"), d3.utcMinute);
- assert.strictEqual(maybeUtcInterval("1 hour"), d3.utcHour);
- assert.strictEqual(maybeUtcInterval("1 day"), d3.unixDay);
- assert.strictEqual(maybeUtcInterval("1 week"), d3.utcWeek);
- assert.strictEqual(maybeUtcInterval("1 month"), d3.utcMonth);
- assert.strictEqual(maybeUtcInterval("1 year"), d3.utcYear);
- assert.strictEqual(maybeUtcInterval("1 monday"), d3.utcMonday);
- assert.strictEqual(maybeUtcInterval("1 tuesday"), d3.utcTuesday);
- assert.strictEqual(maybeUtcInterval("1 wednesday"), d3.utcWednesday);
- assert.strictEqual(maybeUtcInterval("1 thursday"), d3.utcThursday);
- assert.strictEqual(maybeUtcInterval("1 friday"), d3.utcFriday);
- assert.strictEqual(maybeUtcInterval("1 saturday"), d3.utcSaturday);
- assert.strictEqual(maybeUtcInterval("1 sunday"), d3.utcSunday);
+it("utcInterval('1 periods) returns the expected UTC interval", () => {
+ assert.strictEqual(utcInterval("1 second"), d3.utcSecond);
+ assert.strictEqual(utcInterval("1 minute"), d3.utcMinute);
+ assert.strictEqual(utcInterval("1 hour"), d3.utcHour);
+ assert.strictEqual(utcInterval("1 day"), d3.unixDay);
+ assert.strictEqual(utcInterval("1 week"), d3.utcWeek);
+ assert.strictEqual(utcInterval("1 month"), d3.utcMonth);
+ assert.strictEqual(utcInterval("1 year"), d3.utcYear);
+ assert.strictEqual(utcInterval("1 monday"), d3.utcMonday);
+ assert.strictEqual(utcInterval("1 tuesday"), d3.utcTuesday);
+ assert.strictEqual(utcInterval("1 wednesday"), d3.utcWednesday);
+ assert.strictEqual(utcInterval("1 thursday"), d3.utcThursday);
+ assert.strictEqual(utcInterval("1 friday"), d3.utcFriday);
+ assert.strictEqual(utcInterval("1 saturday"), d3.utcSaturday);
+ assert.strictEqual(utcInterval("1 sunday"), d3.utcSunday);
});
-it("maybeUtcInterval('1 periods') returns the expected UTC interval", () => {
- assert.strictEqual(maybeUtcInterval("1 seconds"), d3.utcSecond);
- assert.strictEqual(maybeUtcInterval("1 minutes"), d3.utcMinute);
- assert.strictEqual(maybeUtcInterval("1 hours"), d3.utcHour);
- assert.strictEqual(maybeUtcInterval("1 days"), d3.unixDay);
- assert.strictEqual(maybeUtcInterval("1 weeks"), d3.utcWeek);
- assert.strictEqual(maybeUtcInterval("1 months"), d3.utcMonth);
- assert.strictEqual(maybeUtcInterval("1 years"), d3.utcYear);
- assert.strictEqual(maybeUtcInterval("1 mondays"), d3.utcMonday);
- assert.strictEqual(maybeUtcInterval("1 tuesdays"), d3.utcTuesday);
- assert.strictEqual(maybeUtcInterval("1 wednesdays"), d3.utcWednesday);
- assert.strictEqual(maybeUtcInterval("1 thursdays"), d3.utcThursday);
- assert.strictEqual(maybeUtcInterval("1 fridays"), d3.utcFriday);
- assert.strictEqual(maybeUtcInterval("1 saturdays"), d3.utcSaturday);
- assert.strictEqual(maybeUtcInterval("1 sundays"), d3.utcSunday);
+it("utcInterval('1 periods') returns the expected UTC interval", () => {
+ assert.strictEqual(utcInterval("1 seconds"), d3.utcSecond);
+ assert.strictEqual(utcInterval("1 minutes"), d3.utcMinute);
+ assert.strictEqual(utcInterval("1 hours"), d3.utcHour);
+ assert.strictEqual(utcInterval("1 days"), d3.unixDay);
+ assert.strictEqual(utcInterval("1 weeks"), d3.utcWeek);
+ assert.strictEqual(utcInterval("1 months"), d3.utcMonth);
+ assert.strictEqual(utcInterval("1 years"), d3.utcYear);
+ assert.strictEqual(utcInterval("1 mondays"), d3.utcMonday);
+ assert.strictEqual(utcInterval("1 tuesdays"), d3.utcTuesday);
+ assert.strictEqual(utcInterval("1 wednesdays"), d3.utcWednesday);
+ assert.strictEqual(utcInterval("1 thursdays"), d3.utcThursday);
+ assert.strictEqual(utcInterval("1 fridays"), d3.utcFriday);
+ assert.strictEqual(utcInterval("1 saturdays"), d3.utcSaturday);
+ assert.strictEqual(utcInterval("1 sundays"), d3.utcSunday);
});
-it("maybeUtcInterval('n seconds') returns the expected UTC interval", () => {
+it("utcInterval('n seconds') returns the expected UTC interval", () => {
const start = new Date("2012-01-01T12:01:02");
const end = new Date("2012-01-01T12:14:08");
- assert.deepStrictEqual(maybeUtcInterval("5 seconds").range(start, end), d3.utcSecond.every(5).range(start, end));
- assert.deepStrictEqual(maybeUtcInterval("15 seconds").range(start, end), d3.utcSecond.every(15).range(start, end));
- assert.deepStrictEqual(maybeUtcInterval("45 seconds").range(start, end), d3.utcSecond.every(45).range(start, end));
+ assert.deepStrictEqual(utcInterval("5 seconds").range(start, end), d3.utcSecond.every(5).range(start, end));
+ assert.deepStrictEqual(utcInterval("15 seconds").range(start, end), d3.utcSecond.every(15).range(start, end));
+ assert.deepStrictEqual(utcInterval("45 seconds").range(start, end), d3.utcSecond.every(45).range(start, end));
});