Skip to content

Charts

HeatmapChart

Density and pattern visualization as calendar grids and hour-by-day matrices.

<script>
  import { HeatmapChart } from "@codeatlasdev/ui/charts";
</script>

<HeatmapChart variant="calendar" data={[["2026-03-01", 4]]} range={["2026-01-01", "2026-09-15"]} />
<HeatmapChart variant="matrix" matrixData={[[0, 0, 3]]} xCategories={hours} yCategories={days} />

variant is required. The calendar variant reads data and range; the matrix variant reads matrixData, xCategories and yCategories.

#198

Calendar heatmap

Daily commit activity from January to September.

Reference #198 · Pick in the gallery

Code
svelte
<script lang="ts">
  import { Card } from '@codeatlasdev/ui';
  import { HeatmapChart, type CalendarHeatmapPoint } from '@codeatlasdev/ui/charts';

  // [ 'YYYY-MM-DD', value ] per day.
  const data: CalendarHeatmapPoint[] = Array.from({ length: 258 }, (_, i) => {
    const d = new Date(Date.UTC(2026, 0, 1 + i));
    const weekend = d.getUTCDay() === 0 || d.getUTCDay() === 6;
    const v = weekend
      ? Math.max(0, Math.round(Math.sin(i * 0.3 + 1.4) * 2 + 1))
      : Math.max(0, Math.min(20, Math.round(Math.sin(i * 0.08 + 1.4) * 5 + Math.sin(i * 0.21 + 1.8) * 3 + 8)));
    return [d.toISOString().slice(0, 10), v];
  });
</script>

<Card material="glass" full>
  <HeatmapChart variant="calendar" {data} range={['2026-01-01', '2026-09-15']} tooltipFormatter={(v) => `${v} commits`} height="160px" />
</Card>
#199

Hour by day matrix

Points are [xIndex, yIndex, value] into xCategories and yCategories.

Reference #199 · Pick in the gallery

Code
svelte
<script lang="ts">
  import { Card } from '@codeatlasdev/ui';
  import { HeatmapChart, type MatrixHeatmapPoint } from '@codeatlasdev/ui/charts';

  const hours = Array.from({ length: 24 }, (_, i) => String(i).padStart(2, '0') + ':00');
  const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];

  // [ xIndex, yIndex, value ]
  const matrixData: MatrixHeatmapPoint[] = [];
  for (let d = 0; d < 7; d++) {
    for (let h = 0; h < 24; h++) {
      let v = 0;
      if (h >= 9 && h <= 17 && d < 5) v = Math.round(Math.exp(-Math.pow(h - 10.5, 2) / 4) * 9 + Math.exp(-Math.pow(h - 14.5, 2) / 3) * 7);
      else if (h >= 20 && h <= 23 && d < 5) v = Math.round(Math.sin(h * 0.5 + d) * 1.5 + 1);
      matrixData.push([h, d, Math.max(0, Math.min(10, v))]);
    }
  }
</script>

<Card material="glass" full>
  <HeatmapChart variant="matrix" {matrixData} xCategories={hours} yCategories={days} tooltipFormatter={(v) => `${v} tasks`} height="320px" />
</Card>
#200

Year toggle

Swap data and range to move between years.

Reference #200 · Pick in the gallery

Code
svelte
<script lang="ts">
  import { Card, Flex, Button } from '@codeatlasdev/ui';
  import { HeatmapChart, type CalendarHeatmapPoint } from '@codeatlasdev/ui/charts';

  function gen(year: number, count: number, seed: number): CalendarHeatmapPoint[] {
    return Array.from({ length: count }, (_, i) => {
      const d = new Date(Date.UTC(year, 0, 1 + i));
      const weekend = d.getUTCDay() === 0 || d.getUTCDay() === 6;
      const v = weekend
        ? Math.max(0, Math.round(Math.sin(i * 0.3 + seed) * 2 + 1))
        : Math.max(0, Math.min(20, Math.round(Math.sin(i * 0.08 + seed) * 5 + Math.sin(i * 0.21 + seed * 1.3) * 3 + 8)));
      return [d.toISOString().slice(0, 10), v];
    });
  }

  const data = { 2026: gen(2026, 258, 1.4), 2025: gen(2025, 365, 2.1) };
  const ranges: Record<2025 | 2026, [string, string]> = {
    2026: ['2026-01-01', '2026-09-15'],
    2025: ['2025-01-01', '2025-12-31'],
  };

  let year = $state<2025 | 2026>(2026);
</script>

<div class="wrap">
  <Flex gap="2">
    <Button variant={year === 2026 ? 'filled' : 'glass'} size="sm" onclick={() => (year = 2026)}>2026</Button>
    <Button variant={year === 2025 ? 'filled' : 'glass'} size="sm" onclick={() => (year = 2025)}>2025</Button>
  </Flex>
  <Card material="glass" full>
    <HeatmapChart variant="calendar" data={data[year]} range={ranges[year]} tooltipFormatter={(v) => `${v} commits`} height="160px" />
  </Card>
</div>

<style>
  .wrap { width: 100%; display: flex; flex-direction: column; gap: var(--ca-space-3); }
</style>

Props

PropTypeDefaultDescription
variant'calendar' | 'matrix'–Which layout to render. Required.
dataCalendarHeatmapPoint[][]Calendar variant: [date as YYYY-MM-DD, value] per day.
range[string, string]–Calendar variant: first and last date shown.
matrixDataMatrixHeatmapPoint[][]Matrix variant: [xIndex, yIndex, value].
xCategoriesstring[][]Matrix variant: x-axis labels.
yCategoriesstring[][]Matrix variant: y-axis labels.
colorstring–Hex or rgb color of the high end of the ramp. Defaults to the first palette color. Use hex or rgb, not oklch.
maxnumber–Value that maps to the full color. Defaults to the data maximum.
tooltipFormatter(value: number) => string–Formats the value in the tooltip.
heightstring'240px'CSS height of the chart.
classstring''Extra class names.