Aggregation Timeline
A time series with a drag-to-select range brush, on Chart.js — no d3, no date adapter, gap-filled buckets.
A date aggregation's buckets, plotted as a stepped line with an optional drag-to-select brush — replacing an ~800-line d3 timeline with Chart.js alone, plus a category axis and a small brush plugin.
Optional peer dependency
Ships from @sinequa/atomic-angular/charts, same as <AggregationChart> — see that
page for the chart.js install note and the shared <ChartCanvas> lifecycle rules.
Minimal example
import { Component, signal } from "@angular/core";
import { AggregationTimelineComponent } from "@sinequa/atomic-angular/charts";
import type { TimelineRange } from "@sinequa/atomic-angular/charts";
import type { TimelineSeriesInput } from "@sinequa/atomic-angular/charts";
@Component({
selector: "sample-component",
imports: [AggregationTimelineComponent],
template: `
<div class="h-64">
<AggregationTimeline [series]="series()" (rangeSelected)="onRange($event)" />
</div>
`,
})
export class SampleComponent {
readonly series = signal<TimelineSeriesInput[]>([]);
protected onRange(range: TimelineRange) {
console.log(`Zoom into ${range.from} .. ${range.to}`);
}
}How it works
A category axis, never "time" — this library ships no Chart.js date adapter, and setting
scales.x.type = "time" without one compiles perfectly and throws at runtime. Bucket labels are resolved by
buildTimeline() (a pure function, unit-testable without a chart), which also fills gaps: an empty bucket is
drawn flat at zero rather than skipped, so the shape of the series is never silently misrepresented.
(rangeSelected) only reports a range — it does not zoom anything on its own. If nothing in the host reacts
to it, dragging paints a selection rectangle that then disappears and nothing else happens; the component is
working as designed. Keep a stack of ranges in the host: a drag pushes one (zoom in), a control pops it (zoom
out).
Recipes
Comparing two periods
dashSecondary renders every second series dashed, the "previous period" convention, and pairs it with the
same color as the series it compares against rather than doubling the palette.
import { Component, signal } from "@angular/core";
import { AggregationTimelineComponent } from "@sinequa/atomic-angular/charts";
import type { TimelineSeriesInput } from "@sinequa/atomic-angular/charts";
@Component({
selector: "period-comparison",
imports: [AggregationTimelineComponent],
template: `
<div class="h-64">
<AggregationTimeline [series]="series()" [dashSecondary]="true" mask="YYYY-MM-DD" />
</div>
`,
})
export class PeriodComparisonComponent {
// This-period and previous-period series, interleaved: [current, previous, current, previous, ...].
readonly series = signal<TimelineSeriesInput[]>([]);
}Options
Prop
Type
Pitfalls
What's next
Aggregation Chart
A Sinequa aggregation as a bar, pie or doughnut chart, on Chart.js — an optional peer dependency, from a separate entry point.
Aggregation Heatmap
The canvas sibling of Heatmap, for a two-dimensional distribution too large for the DOM — same inputs, same output payloads, one import change.