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.
<Heatmap> is the one to reach for first — it costs no dependency and is fully accessible.
<AggregationHeatmap> exists for the case <Heatmap> cannot serve: a matrix large enough that hundreds of DOM
nodes become the bottleneck. Canvas rendering is flat in the cell count; a DOM grid is not.
Two costs, one thing you do not lose
Switching to this component costs a dependency (chartjs-chart-matrix, on top of chart.js) and it costs
accessibility — a canvas is opaque to screen readers and to text selection, and nothing brings that back.
What it does not cost is the clickable axis label: createAxisClickPlugin() reproduces it on canvas, and
(axisSelected) emits the exact same payload shape as <Heatmap>.
Minimal example
import { Component, signal } from "@angular/core";
import { AggregationHeatmapComponent } from "@sinequa/atomic-angular/charts/heatmap";
import type { AggregationLike, HeatmapAxisSelection, HeatmapCellSelection } from "@sinequa/atomic-angular";
@Component({
selector: "sample-component",
imports: [AggregationHeatmapComponent],
template: `
<div class="h-96">
<AggregationHeatmap
[aggregation]="matrix()"
[maxX]="60"
[maxY]="60"
(cellSelected)="onCell($event)"
(axisSelected)="onAxis($event)"
/>
</div>
`,
})
export class SampleComponent {
readonly matrix = signal<AggregationLike | undefined>(undefined);
protected onCell(selection: HeatmapCellSelection) {
console.log(`${selection.x} / ${selection.y}: ${selection.count}`);
}
protected onAxis(selection: HeatmapAxisSelection) {
console.log(`Filter the whole ${selection.axis} axis on`, selection.value);
}
}# only if you use @sinequa/atomic-angular/charts/heatmap
npm i chart.js chartjs-chart-matrixHow it works
chartjs-chart-matrix ships no other chart in this library needs, so it lives in its own tertiary entry point
(@sinequa/atomic-angular/charts/heatmap) rather than the shared /charts one — an application drawing only
bar charts never resolves it.
The same buildHeatmap() pure function <Heatmap> uses parses the aggregation here too, so
the two components are interchangeable: identical inputs, identical (cellSelected)/(axisSelected) payload
shapes. Swapping one for the other is an import change, nothing more.
Clickable axis labels, reproduced on canvas. Chart.js's own options.onClick never fires on an axis
label — it only fires inside the chart area, and labels sit outside it by construction. createAxisClickPlugin()
does its own hit test against the scale's box instead, walking getPixelForTick() rather than inverting
getValueForPixel() (which assumes uniform spacing and breaks under offset/autoSkip, both of which this
component sets).
Options
Prop
Type