A line chart shows the trend. Annotations explain why the trend bent — and what it should be measured against. They are reference markers placed on the chart’s axes: a halving date, a product release, a break-even level, a target band. Without them, the reader is left to guess which kink in the line corresponds to which event, or whether the current value is good or bad.
RareCharts supports four kinds of annotations within a single annotations array:
- Point — a single date with a label. Drawn as a vertical line spanning the full plot height, with the label in the reserved area above the chart.
- Range — a date range with optional fill. Drawn as a translucent band between two boundary lines. Useful for periods (a bear market, a freeze window, an A/B test).
- Horizontal line — a reference level at a Y value. Drawn as a horizontal line spanning the full plot width, with an inline label. Useful for break-even, targets, KPI thresholds.
- Horizontal band — a Y-value range with optional fill. Useful for tolerance windows or “acceptable range” bands.
Annotations are supported on Line, DualAxes, and TimeSeries charts. The kind is inferred from which fields are present — date, from/to, value, or yFrom/yTo.
The chart above combines all three common cases: a point annotation on the 4th BTC halving (2024-04-19), a range annotation for the post-election rally window, and a horizontal line at the $100k psychological level. All three are out-of-the-box visuals — no custom SVG, no overlays. The chart automatically reserves vertical space above the plot for the date labels.
Configuration
Pass an annotations array on the chart options. Each entry is one of four kinds, inferred from its fields:
new RareCharts.Line('#chart', {
height: 360,
annotations: [
// Point — vertical line at a date
{
date: '2024-04-19',
label: '4th Halving',
color: '#888',
},
// Range — vertical band between two dates
{
from: '2024-11-05',
to: '2025-01-20',
label: 'Post-election rally',
color: '#00c97a',
fillOpacity: 0.06,
},
// Horizontal line — reference level at a Y value
{
value: 100_000,
label: '$100k',
color: '#fa8c16',
labelPosition: 'left',
},
// Horizontal band — between two Y values
{
yFrom: 80_000,
yTo: 100_000,
label: 'Support zone',
fillOpacity: 0.05,
},
],
}).setData(values);
Dates accept any format understood by the chart’s date parser: ISO strings, timestamps, or Date objects. Y values are plain numbers in the same units as the data series.
Horizontal annotations vs. constant series
The classic way to draw a reference level is to add a series with a constant value. That works, but it has costs: the constant series stretches the Y domain (a far-out break-even pulls the axis), shows up in the crosshair tooltip on every point, and clutters the legend.
Horizontal annotations sidestep all of that. They’re purely visual — they don’t participate in domain calculation, they don’t appear in the tooltip, and they don’t belong to the legend. Use them for break-even lines, KPI targets, support/resistance levels, tolerance bands.
DualAxes — choosing an axis
For a DualAxes chart, horizontal annotations need to specify which Y axis they reference:
new RareCharts.DualAxes('#chart', {
annotations: [
{ value: 14.50, axis: 'y2', label: 'Break-even, USD' },
{ value: 100_000, axis: 'y1', label: 'BTC $100k' },
],
});
axis defaults to 'y1'. Vertical (date-based) annotations don’t need this — they span both axes by definition.
Layout
Labels are rendered above the plot area. The chart automatically pushes its top margin down by annotationLabelHeight + 4 pixels when at least one annotation is configured, so labels never collide with the line. The default height is 22. Override it when you need taller labels (multi-line, larger font) or want to compact the layout:
new RareCharts.Line('#chart', {
annotations: [{ date: '2024-04-19', label: '4th Halving' }],
annotationLabelHeight: 28,
});
If you provide an explicit margin.top it will be respected — but you must reserve enough room yourself.
View clipping
Annotations whose date(s) fall outside the visible X extent are skipped automatically. This is the expected behavior when used together with timeframes, navigator, or setView(): as the user zooms or pans, in-range annotations appear and out-of-range ones disappear. For range annotations partially visible, the fill is clamped to the visible portion and only the boundary line(s) inside the extent are drawn.
Styling
Annotations inherit the muted theme color by default so they don’t compete with the data. Per-annotation overrides:
| Field | Type | Default | Description |
|---|---|---|---|
Point annotation |
|||
date |
Date | string | number | — | Required. The X position of the marker. |
label |
string | '' |
Text rendered above the chart. Empty string suppresses the label, line stays visible. |
color |
CSS color | theme.muted |
Stroke color of the vertical line and default label color. |
strokeDash |
string | 'dashed' |
Line pattern: 'solid', 'dashed', 'dotted', 'dashDot', 'longDash'. |
labelColor |
CSS color | same as color |
Label text color, when you want it different from the line. |
Range annotation |
|||
from |
Date | string | number | — | Required. Range start. |
to |
Date | string | number | — | Required. Range end. If to < from, they are swapped. |
label |
string | '' |
Text rendered above the chart, centered over the visible portion of the range. |
color |
CSS color | theme.muted |
Boundary line color and default fill color. |
fill |
CSS color | same as color |
Background fill of the band when you want it independent from the boundary color. |
fillOpacity |
number | 0.08 |
Opacity of the fill band, 0–1. |
strokeDash |
string | 'dashed' |
Boundary line pattern. |
labelColor |
CSS color | same as color |
Label text color override. |
Horizontal line |
|||
value |
number | — | Required. The Y position of the reference line. |
axis |
'y1' | 'y2' |
'y1' |
Which Y axis the value belongs to. Only relevant for DualAxes. |
label |
string | '' |
Text rendered inline next to the line. |
labelPosition |
'left' | 'right' |
'left' |
Which end of the line the label is anchored to. Pick 'right' if your Y axis is on the left and the right edge is free. |
color |
CSS color | theme.muted |
Stroke color and default label color. |
strokeDash |
string | 'dashed' |
Line pattern. |
labelColor |
CSS color | same as color |
Label text color override. |
Horizontal band |
|||
yFrom |
number | — | Required. Lower Y value of the band. |
yTo |
number | — | Required. Upper Y value. Order is normalized. |
axis |
'y1' | 'y2' |
'y1' |
Which Y axis the values belong to. |
label |
string | '' |
Text rendered inline at the top edge of the band. |
labelPosition |
'left' | 'right' |
'left' |
Which end of the band the label is anchored to. |
color |
CSS color | theme.muted |
Boundary line color and default fill color. |
fill |
CSS color | same as color |
Background fill of the band when independent from the boundary color. |
fillOpacity |
number | 0.08 |
Opacity of the fill band, 0–1. |
strokeDash |
string | 'dashed' |
Boundary line pattern. |
labelColor |
CSS color | same as color |
Label text color override. |
Chart-level options
| Option | Type | Default | Description |
|---|---|---|---|
annotations |
array | — | Array of point and/or range annotations. Mixed entries are allowed. |
annotationLabelHeight |
number | 22 |
Pixels reserved above the chart for annotation labels. Increase if labels are clipped, decrease for a tighter layout. |
When to use them
Annotations are content, not decoration. A good annotation answers a question the chart raises:
- “Why did hashrate drop in April 2024?” → halving annotation.
- “Why did revenue plateau in Q3?” → range covering the marketing freeze.
- “When did the new pricing roll out?” → point on launch day.
Avoid annotating every minor event. The chart starts to look like a footnote index, and the reader stops reading them. Three or four well-chosen markers are usually enough — the rest belongs in the article body.