Skip to content

Axes

Axis types: category (bands), number, time, log. Binding is by position: bottom/top — the X axis, left/right — the Y axis.

Time axis

time accepts a Date, a timestamp or an ISO string; ticks snap to calendar boundaries, and the label format depends on the step (hours → days → months → years).

ts
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';

export function createOptions(): ChartOptions {
  return {
    data: getData(),
    title: { text: 'Metric over Time' },
    series: [{ type: 'line', xField: 'date', yField: 'value', name: 'Value', marker: { enabled: false } }],
    axes: [
      { type: 'time', position: 'bottom' },
      { type: 'number', position: 'left' },
    ],
    legend: { enabled: false },
  };
}
ts
export function getData() {
  const start = Date.UTC(2025, 0, 1);
  const day = 24 * 60 * 60 * 1000;
  const values = [41, 43, 47, 45, 49, 53, 51, 56, 58, 55, 61, 64, 62, 67, 70, 68, 73, 71, 76, 79, 77, 82, 85, 83, 88, 86, 91, 94, 92, 97];
  return values.map((value, index) => ({ date: new Date(start + index * 3 * day), value }));
}

Logarithmic axis

log — for data growing by orders of magnitude; ticks at powers of base (10 by default).

ts
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';

export function createOptions(): ChartOptions {
  return {
    data: getData(),
    title: { text: 'Exponential Growth' },
    subtitle: { text: 'logarithmic Y axis' },
    series: [{ type: 'line', xField: 'year', yField: 'users', name: 'Users' }],
    axes: [
      { type: 'category', position: 'bottom' },
      { type: 'log', position: 'left' },
    ],
    legend: { enabled: false },
  };
}
ts
export function getData() {
  return [
    { year: '2018', users: 120 },
    { year: '2019', users: 540 },
    { year: '2020', users: 2400 },
    { year: '2021', users: 9800 },
    { year: '2022', users: 41000 },
    { year: '2023', users: 165000 },
    { year: '2024', users: 720000 },
    { year: '2025', users: 2900000 },
  ];
}

Hierarchical categories

grouped-category: data values are [group, item] arrays; a row of groups with separators appears below the item labels:

ts
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';

export function createOptions(): ChartOptions {
  return {
    data: getData(),
    title: { text: 'Revenue by Product Category' },
    subtitle: { text: '$B, grouped categories year → quarter' },
    series: [
      { type: 'bar', xField: 'period', yField: 'iphone', name: 'iPhone' },
      { type: 'bar', xField: 'period', yField: 'mac', name: 'Mac' },
      { type: 'bar', xField: 'period', yField: 'services', name: 'Services' },
    ],
    axes: [
      { type: 'grouped-category', position: 'bottom' },
      { type: 'number', position: 'left' },
    ],
  };
}
ts
export function getData() {
  return [
    { period: ['2018', 'Q1'], iphone: 140, mac: 16, services: 20 },
    { period: ['2018', 'Q2'], iphone: 124, mac: 20, services: 30 },
    { period: ['2018', 'Q3'], iphone: 112, mac: 20, services: 36 },
    { period: ['2018', 'Q4'], iphone: 118, mac: 24, services: 36 },
    { period: ['2019', 'Q1'], iphone: 124, mac: 18, services: 26 },
    { period: ['2019', 'Q2'], iphone: 108, mac: 20, services: 40 },
    { period: ['2019', 'Q3'], iphone: 96, mac: 22, services: 42 },
    { period: ['2019', 'Q4'], iphone: 104, mac: 22, services: 40 },
  ];
}

CrossLines

Reference lines and ranges in axis coordinates — with labels:

ts
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';

export function createOptions(): ChartOptions {
  return {
    data: getData(),
    title: { text: 'Latency p95' },
    series: [{ type: 'line', xField: 'month', yField: 'latency', name: 'p95, ms' }],
    axes: [
      {
        type: 'category',
        position: 'bottom',
        crossLines: [{ type: 'range', range: ['Apr', 'May'], label: { text: 'incident' } }],
      },
      {
        type: 'number',
        position: 'left',
        crossLines: [{ value: 200, stroke: '#e5484d', label: { text: 'SLO 200 ms', color: '#e5484d' } }],
      },
    ],
    legend: { enabled: false },
  };
}
ts
export function getData() {
  return [
    { month: 'Jan', latency: 182 },
    { month: 'Feb', latency: 174 },
    { month: 'Mar', latency: 196 },
    { month: 'Apr', latency: 230 },
    { month: 'May', latency: 218 },
    { month: 'Jun', latency: 187 },
    { month: 'Jul', latency: 171 },
    { month: 'Aug', latency: 165 },
  ];
}

Axis options

BlockOptions
number/logmin, max, nice, base (log)
timemin, max (Date/timestamp)
categorypaddingInner, paddingOuter

Full option list

OptionTypeDefaultDescription
type'number' | 'category' | 'time' | 'log' | 'ordinal-time' | 'grouped-category'based on seriesaxis type
position'bottom' | 'left' | 'top' | 'right'based on typeaxis side
title.enabledbooleantrue when text is setaxis title
title.textstringtitle text
title.fontSizePixels12title font size
title.colorColorValueforegroundtitle color
line.enabledbooleantrue (heatmap — off)axis line
line.strokeColorValuetheme mutedline color
line.widthPixels1line width
tick.enabledbooleantrue (heatmap — off)ticks
tick.sizePixels6tick length
tick.widthPixels1tick width
tick.strokeColorValuetheme mutedtick color
label.enabledbooleantruetick labels
label.fontSizePixels11label font size
label.fontFamilystringtheme fonttypeface
label.colorColorValuetheme mutedlabel color
label.spacingPixels4gap between label and tick
label.formatstringformat string (',.2f', '.0%', '%d %b')
label.formatter({ value, index }) => stringprogrammatic formatting
label.avoidCollisionsbooleantrueskip overlapping labels
gridLine.enabledbooleantrue (heatmap — off)grid lines
gridLine.strokeColorValuetheme gridgrid color
gridLine.widthPixels1width
gridLine.lineDashPixels[]grid dash pattern
interval.valuesunknown[]autoexplicit tick values
interval.minSpacingPixels8minimum label spacing
crossLines[].type'line' | 'range''line'line or range
crossLines[].valuevalueline coordinate
crossLines[].range[from, to]fill range
crossLines[].strokeColorValuetheme mutedline color
crossLines[].strokeWidthPixels1line width
crossLines[].lineDashPixels[]dash pattern
crossLines[].fillColorValuetheme mutedrange fill
crossLines[].fillOpacityFraction0.12fill opacity
crossLines[].label.textstringlabel text
crossLines[].label.colorColorValuetheme mutedlabel color
crossLines[].label.fontSizePixels11label font size
min (number, log)numberdata domainlower bound
max (number, log)numberdata domainupper bound
nice (number)booleantrueround the domain to “nice” bounds
base (log)number10logarithm base
paddingInner (category, grouped-category)Fraction0.2 (ordinal-time 0.25)inner band padding
paddingOuter (category, ordinal-time, grouped-category)Fraction0.1outer band padding

Horizontal axis labels are automatically thinned out when crowded (label.avoidCollisions: false disables this).

Overlays

The “no data” and “loading” states are enabled by default: empty data shows overlays.noData.text, and loading: true shows overlays.loading.text.