Add heat map chart visualization component

What does this MR do and why?

Adds a new heat map chart component for analytics dashboards: a grid of shaded cells built for the "Sessions by tier and capability" panel on the Adoption tab of the DAP Impact dashboard.

  • Props are semantic cells, [{ column, row, value }], plus an options object. The component derives the two category axes and the [x, y, value] triples ECharts expects. It carries no query-language concepts, so a follow-up GLQL display type will wrap it and own that translation — the same split used by the existing bar list chart and its GLQL presenter.
  • It is deliberately not registered in the visualization registry, so no dashboard can select it yet. Registration is left for a follow-up MR.
  • Built on GlChart rather than GlHeatmap. GlHeatmap's tooltip hangs off an xAxis axis pointer, so it resolves the hovered column, not the hovered cell, and pins the popover to one cell of that column. This component listens to ECharts item events instead, which give the exact cell, and renders a GlPopover anchored to it.
  • Shading extends heatmapHues (GitLab UI's only sequential ramp) with the two lighter steps of the same data-blue scale, because that ramp starts at data blue 200 and leaves nothing to separate small counts. A neutral is reserved for cells with no activity, so a count of one reads as a real value rather than as absent.
  • Band cut-offs are logarithmic, because these counts are heavily skewed — one cell can be thousands of times another — and equal-width bands would leave nearly every cell in the lowest band. A caller can pass explicit cut-offs via options.bands.
  • The in-cell value label picks whichever neutral extreme has the higher WCAG contrast ratio against its own band, using gitlab-ui's colorFromBackground. Every band clears AA.
  • The ramp reverses and its neutral darkens in dark mode, following the contribution calendar's pattern, so a busier cell stays the more prominent one in either theme.
  • Column labels are truncated to a share of the available width, and every column keeps a label. Angled labels were tried first and rejected: they were hard to read and got clipped at the bottom of the panel.
  • Row height is derived rather than fixed. Rows stretch to fill the available space between a 32px floor and a 120px ceiling, taking GlChart's exported defaultHeight as the target, so a two-row grid does not leave a panel half empty and a seventeen-row grid does not grow without bound. This differs deliberately from bar_list_chart, which takes an exact height from its row count because a bar list is a list of fixed-height rows; a heat map's cells have no single correct height.
  • Cells are explicitly layered above the grid background, which otherwise painted over them.

One open question worth a design opinion: the design prototype draws six shades, GitLab UI's heatmapHues publishes four blues, and this component extends it to six using the two lighter steps of the same data-blue token scale rather than forking a local palette.

References

Screenshots or screen recordings

Screenshot 2026-09-08 at 10.23.31 PM.png

This screenshot predates the column-label and row-height changes described above.

How to set up and validate locally

  1. Run yarn storybook:start.
  2. Open the story at analytics/analytics_dashboards/components/visualizations/heat_map_chart.
  3. Check the six stories: Default, UnitInTooltip, WithEmptyCells, LongRowLabels, CrowdedGrid, InDashboardPanel.
  4. Pay particular attention to CrowdedGrid: it is the worst case a query can reach, seventeen rows down the side and twenty-six weekly buckets across the top, with rows at their minimum height and column labels at their minimum width. It is the place to judge whether truncation is still readable.
  5. Hover a cell and confirm the tooltip names that exact cell and follows it.
  6. Toggle Storybook's dark mode and confirm busier cells stay the more prominent ones.
  7. Run yarn jest spec/frontend/analytics/analytics_dashboards/components/visualizations/heat_map_chart_spec.js (68 tests).

The spec mounts a real ECharts instance over several data shapes, because a heatmap series without a visual map fails at render rather than at build.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist.

Edited by Rudy Crespo

Merge request reports

Loading
Loading