Loading
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 anoptionsobject. 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
GlChartrather thanGlHeatmap.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 aGlPopoveranchored 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 exporteddefaultHeightas 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 frombar_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
- Issue: https://gitlab.com/gitlab-org/gitlab/-/work_items/628031
- Parent epic: https://gitlab.com/groups/gitlab-org/-/work_items/23420
- Bar list chart component this pattern follows: !252906 (merged)
- While building this, three
GlHeatmap/gitlab-ui gaps surfaced that are worth reporting upstream: the built-in tooltip reads axis indices rather than the cell value for[x, y, value]data, tooltip content resolves per column rather than per cell, and there is no dark-mode sequential ramp.
Screenshots or screen recordings
This screenshot predates the column-label and row-height changes described above.
How to set up and validate locally
- Run
yarn storybook:start. - Open the story at
analytics/analytics_dashboards/components/visualizations/heat_map_chart. - Check the six stories: Default, UnitInTooltip, WithEmptyCells, LongRowLabels, CrowdedGrid, InDashboardPanel.
- 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.
- Hover a cell and confirm the tooltip names that exact cell and follows it.
- Toggle Storybook's dark mode and confirm busier cells stay the more prominent ones.
- 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
