Skip to main content

Timeline

Basic Configuration​

The Timeline component has been designed to work together with XY Container. The minimal Timeline configuration looks like:

component.tsx
import { VisXYContainer, VisTimeline } from '@unovis/react'

function Component(props) {
const data: TimeDataRecord[] = props.data
const lineDuration = (d: TimeDataRecord) => d.length
const lineRow = (d: TimeDataRecord) => d.type
const x = (d: TimeDataRecord) => d.timestamp

return (
<VisXYContainer data={data}>
<VisTimeline
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
/>
</VisXYContainer>
)
}
Loading...

where each record should provide at least the following information:

type TimeDataRecord = {
timestamp: Date; // Position on the X axis. Can be `number` or `Date`
duration: number; // Length of the line in X axis values, i.e. milliseconds if you use `Date`
name: string; // The row it will be displayed in
}

Wire these up via the lineDuration and lineRow accessors (along with x for the timestamp).

note

The legacy type and length properties on the Timeline component are deprecated. Use lineRow and lineDuration instead.

Row Labels​

Enable the showRowLabels property to display row types along the vertical axis. You can control the label width with rowLabelWidth (fixed) and rowMaxLabelWidth (maximum) properties.

note

The showLabels, labelWidth, and maxLabelWidth properties are deprecated. Use showRowLabels, rowLabelWidth, and rowMaxLabelWidth instead.

Like other XY components, labeling data along the horizontal axis can be accomplished by adding an Axis component to your container. See following example which displays labeled Timeline alongside a labeled X Axis:

component.tsx
<VisXYContainer data={data}>
<VisAxis type="x" tickFormat={tickFormat}/>
<VisTimeline
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
showRowLabels={true}
/>
</VisXYContainer>
Loading...

Note

Since Timeline groups vertical data in an ordinal fashion, adding a Y axis here is not recommended.

Label Text Align​

Use the rowLabelTextAlign property to control the horizontal alignment of row labels: TextAlign.Left, TextAlign.Center, or TextAlign.Right (default).

<VisTimeline
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
showRowLabels={true}
rowLabelTextAlign="left"
/>
Loading...

Label Width​

Set a fixed label width with rowLabelWidth or a maximum width with rowMaxLabelWidth. Labels longer than the specified value will be trimmed.

<VisTimeline
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
showRowLabels={true}
rowLabelWidth={60}
/>
Loading...

Label Trim Mode​

When labels exceed the available width, they'll be trimmed. Use the rowLabelTrimMode property to control where the trimming occurs: TrimMode.Start, TrimMode.Middle (default), or TrimMode.End.

<VisTimeline
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
showRowLabels={true}
rowLabelWidth={70}
rowLabelTrimMode="end"
/>
Loading...

Label Margin​

Use the rowLabelMargin property to set the spacing (in pixels) between the row labels and the timeline content.

You can also provide a [left, right] tuple to control spacing on both sides of the label independently:

  • The first value sets the left margin (space from the container edge or row icon to the label)
  • The second value sets the right margin (space between the label and the timeline content)
rowLabelMargin: [10, 5] // 10px left, 5px right
<VisTimeline
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
showRowLabels={true}
rowLabelMargin={5}
/>
Loading...

Label Style​

Use rowLabelStyle to apply custom CSS styles to row labels. It accepts an object with CSS property-value pairs or an accessor function for per-label styling.

rowLabelStyle: { 'font-weight': 'bold', 'fill': '#333' }

Label Formatter​

Use rowLabelFormatter to customize the displayed label text. It receives the row key, the row's data items, and the row index.

rowLabelFormatter: (key: string, items: Datum[], i: number) => `${key} (${items.length})`

Icon​

Use the rowIcon property to display an icon before each row label. The function receives the row key, items, and index, and should return a TimelineRowIcon object or undefined.

type TimelineRowIcon = {
href: string; // SVG icon href (defined in container's svgDefs)
size: number;
color: string;
}

Row Configuration​

Alternating row colors​

For easier readability, each row's background color alternates among two colors by default. To display a single background color across all rows, disable the alternatingRowColors property:

<VisTimeline
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
alternatingRowColors={true}
/>
Loading...

Row Height​

Use the rowHeight property to adjust the size of each row.

<VisTimeline
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
rowHeight={50}
/>
Loading...

Filling empty vertical space​

When the timeline container is taller than the combined height of all rows, rowFillEmptySpace (default: true) stretches row layout so the rows use the extra space. Set it to false if you prefer rows to stay compact at the top and leave the remainder of the container empty.

Line Configuration​

Line Cap​

By default, lines have squared ends. You can give your lines a rounded appearance by setting lineCap property to true.

<VisTimeline
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
lineCap={true}
/>
Loading...

Showing empty segments​

Set showEmptySegments to true if you want to display lines that are undefined or too small to see.

<VisTimeline
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
lineCap={true}
showEmptySegments={true}
/>
Loading...

Empty segments positioning​

When both showEmptySegments and lineCap are set to true, you can control the positioning of small segments using the showEmptySegmentsCorrectPosition property. When set to true (default), small segments will be centered at their actual position. When set to false, small segments will be aligned to the left of their position.

<VisTimeline
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
lineCap={true}
showEmptySegments={true}
showEmptySegmentsCorrectPosition={true}
/>
Loading...

Line Width​

You can also change the line thickness with the lineWidth property, which determines how much vertical space each Timeline item occupies.

<VisTimeline
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
rowHeight={50}
lineWidth={10}
/>
Loading...

Line Cursor​

Use the lineCursor property to set a custom CSS cursor when hovering over a timeline line.

note

The cursor property is deprecated. Use lineCursor instead.

Line Icons​

You can display icons at the start and/or end of each timeline line using SVG symbols defined in the container's svgDefs.

PropertyDescription
lineStartIcon / lineEndIconSVG icon href accessor
lineStartIconColor / lineEndIconColorIcon color accessor
lineStartIconSize / lineEndIconSizeIcon size accessor
lineStartIconArrangement / lineEndIconArrangementIcon positioning relative to the line: Arrangement.Inside (default), Arrangement.Outside, Arrangement.Start, Arrangement.Middle, or Arrangement.End

Arrows​

Use the arrows property to draw connecting arrows between timeline lines. Each arrow is defined as a TimelineArrow object:

type TimelineArrow = {
id?: string;
xSource?: number; // X position of arrow start (defaults to source line's end)
xTarget?: number; // X position of arrow end (defaults to target line's start)
xSourceOffsetPx?: number; // Horizontal offset of the source in pixels
xTargetOffsetPx?: number; // Horizontal offset of the target in pixels
lineSourceId: string; // Id of the source line element
lineTargetId: string; // Id of the target line element
lineSourceMarginPx?: number; // Margin between source line and arrow in pixels
lineTargetMarginPx?: number; // Margin between target line and arrow in pixels
arrowHeadLength?: number; // Arrowhead length in pixels (default: 8)
arrowHeadWidth?: number; // Arrowhead width in pixels (default: 6)
}

The lineSourceId and lineTargetId correspond to the values returned by the id accessor on your data items.

component.tsx
function Component(props) {
const data: TimeDataRecord[] = props.data
const arrows = [{ lineSourceId: 'item-0', lineTargetId: 'item-1', xSource: ... }, ...]
const x = (d: TimeDataRecord) => d.timestamp
const id = (d: TimeDataRecord) => d.id
const lineRow = (d: TimeDataRecord) => d.name
const lineDuration = (d: TimeDataRecord) => d.duration

return (
<VisTimeline
x={x}
id={id}
lineRow={lineRow}
lineDuration={lineDuration}
lineCap={true}
rowHeight={35}
showRowLabels={true}
arrows={arrows}
/>
)
}
Loading...

Events​

Scrolling​

You can provide a callback to the onScroll property, which accepts a function of type:

type onScroll = (n: number) => void

where n is equal to the distance scrolled from the top of the timeline (in pixels).

See the following example, where onScroll updates the xAxis label:

component.tsx
function Component(props) {
const data: TimeDataRecord[] = props.data
const onScroll = (n: number) => setAxisLabel(`${n}px from the top`)
const lineDuration = (d: TimeDataRecord) => d.length
const lineRow = (d: TimeDataRecord) => d.type
const x = (d: TimeDataRecord) => d.timestamp

return (
<VisTimeline
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
onScroll={onScroll}
/>
)
}
Loading...

Custom cursor for hover events​

You can set a custom cursor when hovering over a line using the lineCursor property. It'll only be active if you've defined events for [Timeline.selectors.line]:

More Events​

import { Timeline } from '@unovis/ts'

const events = {
[Timeline.selectors.background]: {
wheel: () => { ... },
},
[Timeline.selectors.line]: {
click: () => { ... },
}
[Timeline.selectors.label]: {
mouseover: () => { ... }
}
}

CSS Variables​

The Timeline component supports additional styling via CSS variables:

All supported CSS variables and their default values
--vis-timeline-row-even-fill-color: #FFFFFF;
--vis-timeline-row-odd-fill-color: #F7FAFC;
--vis-timeline-row-background-opacity: 1;
--vis-timeline-scrollbar-background-color: #E6E9F3;
--vis-timeline-scrollbar-color: #9EA7B8;
--vis-timeline-label-font-size: 12px;
--vis-timeline-label-color: #6C778C;
--vis-timeline-label-user-select: none;
--vis-timeline-label-pointer-events: all;
--vis-timeline-arrow-color: #6C778C;
--vis-timeline-arrow-stroke-width: 1.5;
--vis-timeline-cursor: default;
--vis-timeline-line-color: var(--vis-color-main);
--vis-timeline-line-stroke-color: undefined;
--vis-timeline-line-stroke-width: 0;
--vis-timeline-line-hover-stroke-width: 0;
--vis-timeline-line-hover-stroke-color: #6C778C;
--vis-timeline-row-icon-cursor: default;
--vis-dark-timeline-row-even-fill-color: #292B34;
--vis-dark-timeline-row-odd-fill-color: #333742;
--vis-dark-timeline-scrollbar-background-color: #292B34;
--vis-dark-timeline-scrollbar-color: #6C778C;
--vis-dark-timeline-label-color: #EFF5F8;
--vis-dark-timeline-arrow-color: #EFF5F8;
--vis-dark-timeline-line-hover-stroke-color: #EFF5F8;

Component Props​

NameTypeDescription
* required property