Functional Weave
Code in TypeScript

charts.ticks

Axis ticks: a round step (1, 2 or 5 x 10^k), the ticks on it, and calendar ticks from days to years.

1.0.0 · published 2026-10-03 by charlie · Anterra

Pinned by 57 tests, run in TypeScript, Python and Rust.tickStep 16 · niceTicks 12 · timeTickInterval 12 · timeTicks 17

What it does

Where the ticks on an axis go. `niceTicks(0, 1, 10)` is `[0, 0.1, ..., 1]`, `timeTicks("2026-01-01", "2026-12-31", "month", 3)` is the four quarter starts, and `tickStep` and `timeTickInterval` say what spacing to use for about `count` ticks. This is a group: the four functions are the tick half of an axis, used with `charts.scale` and `charts.format`.

## Number ticks

The functions

A group: 4 functions that work together, each in its own file, each pinned by its own tests in TypeScript, Python and Rust. A project can install only the ones it calls.

  1. tickStep (start: float, stop: float, count: int) -> float
  2. niceTicks (start: float, stop: float, count: int) -> float[]
  3. timeTickInterval (start: date, stop: date, count: int) -> TimeTickInterval
  4. timeTicks (start: date, stop: date, interval: TimeInterval, step: int) -> date[]

The types it declares, generated into your project

export type TimeInterval = "day" | "week" | "month" | "quarter" | "year";

/** A calendar interval and how many of it between ticks. */
export interface TimeTickInterval {
  readonly interval: TimeInterval;
  /** 1 or more */
  readonly step: number;
}

Once installed, your code imports each one from the group's module.

tickStep throws on bad input 16 tests

export function tickStep(start: number, stop: number, count: number): number
startfloat
stopfloat
countintroughly how many ticks are wanted, at least 1
returnsfloat1, 2 or 5 times a power of ten, exactly the nearest double to it (0.1, not 0.1000000000000001); 0 when start equals stop

For example

  • tickStep(0, 10, 10) → 1 ten ticks over ten
  • tickStep(0, 100, 10) → 10 ten ticks over a hundred
  • tickStep(0, 1, 10) → 0.1 a tenth, exactly the double 0.1
import { tickStep } from "#fune/charts.ticks@^1";
impl/typescript/tick_step.ts · 46 lines · open · raw
/**
 * The tick step for about `count` ticks between start and stop: 1, 2 or 5
 * times a power of ten, as d3-array's tickIncrement chooses it.
 *
 * The power of ten is found by multiplying whole numbers, never with log10,
 * and a fractional step is returned as factor / 10^k, a single correctly
 * rounded division, so it is exactly the double 0.2 or 0.05 in every
 * language rather than 0.1 * 2 or 10^-2 * 5 with their stray last digits.
 */
export function tickStep(start: number, stop: number, count: number): number {
  const [mul, div] = tickSpec(start, stop, count);
  return mul / div;
}

// Exported for niceTicks, which needs the step as a multiplier or a divisor
// so every tick is one exact operation on a whole number.

/**
 * The step as [multiplier, divisor], one of which is 1: [20, 1] is a step of
 * 20, [1, 5] a step of 0.2. [0, 1] when start equals stop.
 */
export function tickSpec(start: number, stop: number, count: number): [number, number] {
  if (typeof start !== "number" || !Number.isFinite(start) || typeof stop !== "number" || !Number.isFinite(stop)) {
    throw new Error(`start and stop must be finite numbers; got ${start} and ${stop}`);
  }
  if (!Number.isInteger(count) || count < 1) throw new Error(`count must be a whole number of at least 1, got ${count}`);
  const raw = Math.abs(stop - start) / count;
  if (raw === 0) return [0, 1];
  if (raw >= 1) {
    let power = 1;
    while (power * 10 <= raw) power *= 10;
    return [niceFactor(raw / power) * power, 1];
  }
  let inverse = 1;
  while (raw * inverse < 1) inverse *= 10;
  const factor = niceFactor(raw * inverse);
  return factor === inverse ? [1, 1] : [1, inverse / factor];
}

/** d3's rule: round the mantissa (1 to 10) to 1, 2, 5 or 10 on a log scale. */
function niceFactor(error: number): number {
  if (error >= Math.sqrt(50)) return 10;
  if (error >= Math.sqrt(10)) return 5;
  if (error >= Math.sqrt(2)) return 2;
  return 1;
}

niceTicks throws on bad input 12 tests

export function niceTicks(start: number, stop: number, count: number): readonly number[]
startfloat
stopfloat
countintroughly how many ticks are wanted, at least 1
returnsfloat[]the multiples of tickStep between start and stop inclusive, running from start towards stop

For example

  • niceTicks(0, 10, 5) → 0, 2, 4, 6, 8, 10 steps of two
  • niceTicks(0, 1, 10) → 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1 tenths are exact: the fourth tick is 0.3, not 0.30000000000000004
  • niceTicks(0.13, 0.87, 5) → 0.2, 0.4, 0.6, 0.8 ticks inside a messy extent
import { niceTicks } from "#fune/charts.ticks@^1";
impl/typescript/nice_ticks.ts · 43 lines · open · raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

import { roundFloat } from "./math_round_float.ts";  ← from math.round-float ^1.0.0 · built alongside by fune
import { tickSpec } from "./charts_ticks_tick_step.ts";  ← tickStep, another function of this group · built into the same file, even by a slim install

/**
 * Ticks at round values between start and stop, as d3.ticks: every multiple
 * of tickStep in [min, max], in the direction start to stop.
 *
 * Each tick is one exact operation on a whole number, i * step or i / divisor,
 * so the third tick of 0.1 steps is 0.3, not 0.30000000000000004 as adding
 * 0.1 three times gives.
 */
export function niceTicks(start: number, stop: number, count: number): readonly number[] {
  let [mul, div] = tickSpec(start, stop, count);
  if (start === stop) return [start + 0];
  const reverse = stop < start;
  const lo = reverse ? stop : start;
  const hi = reverse ? start : stop;
  let [i1, i2] = indexes(lo, hi, mul, div);
  if (i2 < i1 && count === 1) {
    // No multiple of the step for one tick falls inside; d3 retries with two.
    [mul, div] = tickSpec(start, stop, 2);
    [i1, i2] = indexes(lo, hi, mul, div);
  }
  const ticks: number[] = [];
  for (let i = i1; i <= i2; i++) ticks.push(div > 1 ? i / div : i * mul);
  if (reverse) ticks.reverse();
  return ticks.map((t) => t + 0);
}

function indexes(lo: number, hi: number, mul: number, div: number): [number, number] {
  if (div > 1) {
    let i1 = roundFloat(lo * div, 0);
    let i2 = roundFloat(hi * div, 0);
    if (i1 / div < lo) i1 += 1;
    if (i2 / div > hi) i2 -= 1;
    return [i1, i2];
  }
  let i1 = roundFloat(lo / mul, 0);
  let i2 = roundFloat(hi / mul, 0);
  if (i1 * mul < lo) i1 += 1;
  if (i2 * mul > hi) i2 -= 1;
  return [i1, i2];
}

timeTickInterval throws on bad input 12 tests

export function timeTickInterval(start: string, stop: string, count: number): TimeTickInterval
startdate
stopdate
countintroughly how many ticks are wanted, at least 1
returnsTimeTickInterval

For example

  • timeTickInterval(2026-01-01, 2026-01-11, 10) → interval day, step 1 ten days, ten ticks: daily
  • timeTickInterval(2026-01-01, 2026-01-31, 10) → interval day, step 2 a month, ten ticks: every other day
  • timeTickInterval(2026-01-01, 2026-04-01, 10) → interval week, step 1 a quarter, ten ticks: weekly
import { timeTickInterval } from "#fune/charts.ticks@^1";
impl/typescript/time_tick_interval.ts · 34 lines · open · raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

import { type TimeTickInterval } from "./charts_ticks_types.ts";
import { epochDayFromIso } from "./dates_add_days.ts";  ← from dates.add-days ^1.0.0 · built alongside by fune
import { tickStep } from "./charts_ticks_tick_step.ts";  ← tickStep, another function of this group · built into the same file, even by a slim install

// d3-scale's calendar ladder (its time.js tickIntervals), from a day up, with
// the lengths in days it compares against: a month counts as 30, a quarter as
// 90, a year as 365.
const LADDER: [TimeTickInterval["interval"], number, number][] = [
  ["day", 1, 1],
  ["day", 2, 2],
  ["week", 1, 7],
  ["month", 1, 30],
  ["quarter", 1, 90],
  ["year", 1, 365],
];

/**
 * The calendar interval for about `count` ticks between two dates, as d3's
 * time scale picks it: the rung of the ladder nearest the ideal spacing (by
 * ratio), or whole years in steps of 1, 2 or 5 x 10^k beyond a year.
 */
export function timeTickInterval(start: string, stop: string, count: number): TimeTickInterval {
  if (!Number.isInteger(count) || count < 1) throw new Error(`count must be a whole number of at least 1, got ${count}`);
  const span = Math.abs(epochDayFromIso(stop) - epochDayFromIso(start));
  const target = span / count;
  let i = 0;
  while (i < LADDER.length && LADDER[i][2] <= target) i++;
  if (i === LADDER.length) {
    return { interval: "year", step: Math.max(1, tickStep(0, span / 365, count)) };
  }
  if (i === 0) return { interval: "day", step: 1 };
  const pick = target / LADDER[i - 1][2] < LADDER[i][2] / target ? LADDER[i - 1] : LADDER[i];
  return { interval: pick[0], step: pick[1] };
}

timeTicks throws on bad input 17 tests

export function timeTicks(start: string, stop: string, interval: TimeInterval, step: number): readonly string[]
startdate
stopdate
intervalTimeIntervalday, week (Mondays), month, quarter or year
stepintevery step-th boundary, at least 1: day 2 is the 1st, 3rd, 5th... of each month; month 3 is January, April, July, October
returnsdate[]the boundaries between start and stop inclusive, running from start towards stop

For example

  • timeTicks(2026-01-30, 2026-02-02, day, 1) → 2026-01-30, 2026-01-31, 2026-02-01, 2026-02-02 every day across a month end
  • timeTicks(2026-01-28, 2026-02-04, day, 2) → 2026-01-29, 2026-01-31, 2026-02-01, 2026-02-03 every other day follows the day of the month, restarting on the 1st
  • timeTicks(2024-02-28, 2024-03-01, day, 1) → 2024-02-28, 2024-02-29, 2024-03-01 a leap day
import { timeTicks } from "#fune/charts.ticks@^1";
impl/typescript/time_ticks.ts · 60 lines · open · raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

import { type TimeInterval } from "./charts_ticks_types.ts";
import { civilFromDays, daysFromCivil, epochDayFromIso, isoFromEpochDay } from "./dates_add_days.ts";  ← from dates.add-days ^1.0.0 · built alongside by fune

// 1970-01-05, the first Monday on or after the epoch, as a day number.
const FIRST_MONDAY = 4;
const MAX_TICKS = 10000;

/**
 * Calendar boundaries between two dates, inclusive: every `step`-th day,
 * Monday, 1st of the month, quarter start or 1 January.
 *
 * The steps are anchored to the calendar, not to `start`, so panning an axis
 * does not make its ticks jump: days by day of the month ((day - 1) % step,
 * as d3's timeDay.every), weeks by whole weeks since 1970-01-05, months by
 * (month - 1) % step, quarters by quarter of the year, years by year % step.
 */
export function timeTicks(start: string, stop: string, interval: TimeInterval, step: number): readonly string[] {
  if (!Number.isInteger(step) || step < 1) throw new Error(`step must be a whole number of at least 1, got ${step}`);
  const a = epochDayFromIso(start);
  const b = epochDayFromIso(stop);
  const reverse = b < a;
  const lo = reverse ? b : a;
  const hi = reverse ? a : b;
  const days: number[] = [];
  const add = (day: number) => {
    if (days.length >= MAX_TICKS) throw new Error(`too many ticks: more than ${MAX_TICKS}; use a longer interval or step`);
    days.push(day);
  };

  if (interval === "day") {
    for (let d = lo; d <= hi; d++) {
      if ((civilFromDays(d).day - 1) % step === 0) add(d);
    }
  } else if (interval === "week") {
    let k = Math.ceil((lo - FIRST_MONDAY) / 7);
    k = Math.ceil(k / step) * step;
    for (let d = FIRST_MONDAY + 7 * k; d <= hi; d += 7 * step) add(d);
  } else if (interval === "month" || interval === "quarter" || interval === "year") {
    const months = interval === "month" ? step : interval === "quarter" ? 3 * step : 12;
    const first = civilFromDays(lo);
    let year = first.year;
    let month = first.month;
    for (;;) {
      const d = daysFromCivil(year, month, 1);
      if (d > hi) break;
      const onStep = interval === "year" ? month === 1 && year % step === 0 : (month - 1) % months === 0;
      if (d >= lo && onStep) add(d);
      month += 1;
      if (month > 12) {
        month = 1;
        year += 1;
      }
    }
  } else {
    throw new Error(`unknown time interval "${interval}"`);
  }
  const ticks = days.map(isoFromEpochDay);
  if (reverse) ticks.reverse();
  return ticks;
}

Install

fune build

With that line in your source, in a TypeScript project (language typescript in fune.project), fune build resolves it and its 2 dependencies, pins them in fune.lock, downloads only the TypeScript package of each, and builds the code above into your project’s .fune/build, one readable file per capability with a header linking back here. Or pin a range in fune.project and build in one step:

fune add charts.ticks

That builds the whole group. To build only what you call, and whatever it uses inside the group:

fune add charts.ticks --only tickStep
Download for TypeScript charts.ticks-1.0.0-typescript.fune · 25,692 bytes sha256 a6c9c158e2748cc3f724fdb4966764d74b33410fb3b76e6a2ecce040c0593585

The manifest, vectors and README with only the TypeScript implementation. Install it without the registry with fune add ./charts.ticks-1.0.0-typescript.fune, or fetch it from a terminal with fune pull charts.ticks@1.0.0:typescript.

The whole function, every language, is one file too: charts.ticks-1.0.0.fune, 42,760 bytes, sha256 c5ce85e5c19c171b83a7de93b99f92ae8d636f869f8cc071d3ef2bb16c333991. It installs into a project of any language.

Customise it in your app

The seams this capability offers. Put a marker directly above a function of your own and fune build wires it into the built code; the package on the registry is not changed, the built file’s header lists it under CUSTOMISED, and fune hooks lists every hook in the project. How hooks work.

before — your function gets the arguments and returns them, changed or not, or throws to refuse the call.

// fune: before charts.ticks.tickStep
// fune: before charts.ticks.niceTicks
// fune: before charts.ticks.timeTickInterval
// fune: before charts.ticks.timeTicks

after — your function gets the result and the arguments, and returns the final result.

// fune: after charts.ticks.tickStep
// fune: after charts.ticks.niceTicks
// fune: after charts.ticks.timeTickInterval
// fune: after charts.ticks.timeTicks

replace — inside this capability’s code only, calls to a dependency go to your function, with the same signature. Other capabilities that use it are unaffected; write in * to replace it everywhere.

// fune: replace dates.add-days in charts.ticks
// fune: replace math.round-float in charts.ticks

step — your function runs at a numbered point inside a function’s body, receives the in-scope values it names as parameters, and may return replacements. List the points with fune show charts.ticks --steps.

// fune: step charts.ticks.<fn> after <n|label>

Tests

A version published now needs at least 8 tests for every function, and one that expects the error for each function that throws; the registry refuses it otherwise. fune verify --all runs each case in TypeScript, Python and Rust, and a project runs them again with fune verify. This page lists the cases; it does not run them. The exact JSON is vectors.json.

tickStep 16 tests

CaseArgumentsExpected
ten ticks over ten 0, 10, 10 → 1
ten ticks over a hundred 0, 100, 10 → 10
a tenth, exactly the double 0.1 0, 1, 10 → 0.1
a fifth, as 1/5 rather than 0.1 * 2 0, 1, 5 → 0.2
9.7 rounds up to 10 0, 97, 10 → 10
3.7 rounds to 5 0, 37, 10 → 5
1.5 rounds to 2 0, 15, 10 → 2
negative to positive -12.5, 37.2, 5 → 10
a reversed extent still has a positive step 100, 0, 10 → 10
a small fractional step 0, 0.05, 10 → 0.005
Show the other 6 tests
CaseArgumentsExpected
0.7 for one tick rounds to 0.5 0, 0.7, 1 → 0.5
0.9 for one tick rounds up to a whole 1 0, 0.9, 1 → 1
large values 0, 1,234,567, 5 → 200,000
equal ends have no step 5, 5, 10 → 0
count of zero is an error 0, 10, 0 → error: count must be a whole number of at least 1
fractional count is an error 0, 10, 1.5 → error: count must be a whole number of at least 1

niceTicks 12 tests

CaseArgumentsExpected
steps of two 0, 10, 5 → 0, 2, 4, 6, 8, 10
tenths are exact: the fourth tick is 0.3, not 0.30000000000000004 0, 1, 10 → 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1
ticks inside a messy extent 0.13, 0.87, 5 → 0.2, 0.4, 0.6, 0.8
negative to positive, the ends are not ticks -12.5, 37.2, 5 → -10, 0, 10, 20, 30
a reversed extent gives ticks in its direction 10, 0, 5 → 10, 8, 6, 4, 2, 0
equal ends give that one value 5, 5, 10 → 5
one tick 1.2, 3.8, 1 → 2
one tick with no whole number inside retries at two, as d3 does 2.1, 2.9, 1 → 2.5
millions 0, 1,000,000, 4 → 0, 200,000, 400,000, 600,000, 800,000, 1,000,000
thousandths 0.001, 0.006, 4 → 0.001, 0.002, 0.003, 0.004, 0.005
Show the other 2 tests
CaseArgumentsExpected
all negative -1, -0.5, 5 → -1, -0.9, -0.8, -0.7, -0.6, -0.5
count of zero is an error 0, 10, 0 → error: count must be a whole number of at least 1

timeTickInterval 12 tests

CaseArgumentsExpected
ten days, ten ticks: daily 2026-01-01, 2026-01-11, 10 → interval day, step 1
a month, ten ticks: every other day 2026-01-01, 2026-01-31, 10 → interval day, step 2
a quarter, ten ticks: weekly 2026-01-01, 2026-04-01, 10 → interval week, step 1
a year, ten ticks: monthly 2026-01-01, 2027-01-01, 10 → interval month, step 1
a reversed year is the same 2027-01-01, 2026-01-01, 10 → interval month, step 1
two years, five ticks: quarterly 2026-01-01, 2028-01-01, 5 → interval quarter, step 1
a hundred days for one tick is nearer a quarter than a year 2026-01-01, 2026-04-11, 1 → interval quarter, step 1
a decade, five ticks: every two years 2020-01-01, 2030-01-01, 5 → interval year, step 2
fifty years, five ticks: every ten years 1975-01-01, 2025-01-01, 5 → interval year, step 10
the same day: daily 2026-01-01, 2026-01-01, 5 → interval day, step 1
Show the other 2 tests
CaseArgumentsExpected
count of zero is an error 2026-01-01, 2027-01-01, 0 → error: count must be a whole number of at least 1
an impossible date is an error 2026-02-30, 2027-01-01, 5 → error: is not a real calendar date

timeTicks 17 tests

CaseArgumentsExpected
every day across a month end 2026-01-30, 2026-02-02, day, 1 → 2026-01-30, 2026-01-31, 2026-02-01, 2026-02-02
every other day follows the day of the month, restarting on the 1st 2026-01-28, 2026-02-04, day, 2 → 2026-01-29, 2026-01-31, 2026-02-01, 2026-02-03
a leap day 2024-02-28, 2024-03-01, day, 1 → 2024-02-28, 2024-02-29, 2024-03-01
Mondays in September 2026 2026-09-01, 2026-09-30, week, 1 → 2026-09-07, 2026-09-14, 2026-09-21, 2026-09-28
every other Monday, counted from 1970-01-05 2026-09-01, 2026-09-30, week, 2 → 2026-09-14, 2026-09-28
Mondays either side of 1970 1969-12-29, 1970-01-06, week, 1 → 1969-12-29, 1970-01-05
month starts, the first after a mid-month start 2026-01-15, 2026-05-01, month, 1 → 2026-02-01, 2026-03-01, 2026-04-01, 2026-05-01
every third month is January, April, July, October 2026-01-01, 2026-12-31, month, 3 → 2026-01-01, 2026-04-01, 2026-07-01, 2026-10-01
quarter starts across a year end 2025-11-15, 2026-08-01, quarter, 1 → 2026-01-01, 2026-04-01, 2026-07-01
every other quarter 2026-01-01, 2027-01-01, quarter, 2 → 2026-01-01, 2026-07-01, 2027-01-01
Show the other 7 tests
CaseArgumentsExpected
1 January each year 2023-06-01, 2026-01-01, year, 1 → 2024-01-01, 2025-01-01, 2026-01-01
every fifth year falls on multiples of five 2001-03-01, 2021-12-31, year, 5 → 2005-01-01, 2010-01-01, 2015-01-01, 2020-01-01
a reversed extent gives ticks in its direction 2026-02-02, 2026-01-30, day, 1 → 2026-02-02, 2026-02-01, 2026-01-31, 2026-01-30
no month starts inside 2026-01-02, 2026-01-30, month, 1 →
step of zero is an error 2026-01-01, 2026-02-01, day, 0 → error: step must be a whole number of at least 1
an unknown interval is an error 2026-01-01, 2026-02-01, hour, 1 → error: unknown time interval "hour"
more than 10,000 ticks is an error 2000-01-01, 2030-01-01, day, 1 → error: too many ticks: more than 10000

More from the author

`tickStep` is d3-array's rule: divide the extent by `count`, take the power of ten at or below it, and round the leftover factor to 1, 2, 5 or 10 on a log scale (the cut-offs are √2, √10 and √50). `niceTicks` returns every multiple of that step between the two ends inclusive, in the direction from `start` to `stop`; the ends themselves are ticks only if they are multiples. Equal ends give `[start]` (and a step of 0). If one tick is asked for and no multiple falls inside, it tries again for two, as d3 does.

The arithmetic is chosen so that the three languages print the same ticks:

- The power of ten is found by multiplying whole numbers, never with `log10`, whose last bit is platform-dependent. - A fractional step is kept as a whole-number divisor: a step of 0.2 is "divide by 5", so the tick is `i / 5`, one correctly rounded division. Adding 0.1 three times gives 0.30000000000000004; here the third tenth is exactly the double 0.3. `tickStep` returns `factor / 10^k` the same way. - Tick indexes are rounded with `math.round-float` and then corrected by comparison, so a product that lands a hair either side of a whole number cannot add or lose a tick.

## Calendar ticks

`timeTicks` returns the calendar boundaries inside a date range, inclusive:

| interval | a tick on | `step` counts | |-----------|----------------------------------------|----------------------------------------| | `day` | days with (day of month - 1) % step = 0 | restarts each month, as d3's timeDay.every | | `week` | Mondays (ISO weeks) | whole weeks since Monday 1970-01-05 | | `month` | the 1st, (month - 1) % step = 0 | month 3 is January, April, July, October | | `quarter` | 1 January, April, July, October | quarter of the year % step = 0 | | `year` | 1 January, year % step = 0 | every fifth year is 2005, 2010, ... |

Steps are anchored to the calendar, not to the first date, so an axis that pans by a day keeps the same ticks instead of shifting them all. Dates are counted as whole days (via `dates.add-days`), never through a `Date` object, so time zones and clock changes cannot move a tick. More than 10,000 ticks is an error, since it is always a wrong interval.

`timeTickInterval` picks the interval for about `count` ticks the way d3's time scale does: the ideal spacing is the span in days over `count`, and it takes whichever neighbouring rung of the ladder day, 2 days, week, month (30 days), quarter (90 days), year (365 days) is nearer by ratio. Beyond a year it uses whole years in a `tickStep` of 1, 2 or 5 x 10^k.

Sources: Mike Bostock, d3-array `ticks.js` (tickIncrement, ticks) and d3-scale `time.js` (tickIntervals), github.com/d3; ISO 8601 for weeks starting on Monday.

Files

PathBytes
README.md3,230
impl/python/nice_ticks.py1,480
impl/python/tick_step.py1,653
impl/python/time_tick_interval.py1,411
impl/python/time_ticks.py2,374
impl/rust/nice_ticks.rs2,016
impl/rust/tick_step.rs2,109
impl/rust/time_tick_interval.rs1,921
impl/rust/time_ticks.rs3,230
impl/typescript/nice_ticks.ts1,568
impl/typescript/tick_step.ts1,943
impl/typescript/time_tick_interval.ts1,480
impl/typescript/time_ticks.ts2,418
vectors.json7,976