Skip to content

Heatmap 热力图 ​

用于展示一年(或任意区间)内每日的活跃度、提交量、访问量等按天聚合的指标。

何时使用 ​

  • 需要在一屏内看出一年中哪些天数值高、哪些天几乎为零。
  • 数据天然按天聚合,且关注的是分布形态而不是精确数值比较。
  • 常见于贡献图、打卡记录、可用性监控(如服务健康度日历)。

基础用法 ​

默认按自然年渲染:year 指定年份,data 提供每天的数值。没有数据的天会使用 minimumColor。

一三五
1月2月3月4月5月6月7月8月9月10月11月12月
少多
vue
<template>
  <x-heatmap :year="year" :data="data" :aria-label="`${year} 年活跃度`" />
</template>

<script setup lang="ts">
import { ref } from 'vue';

const year = new Date().getFullYear();
const data = ref([
  { timestamp: new Date(year, 0, 3).getTime(), value: 12 },
  { timestamp: new Date(year, 0, 4).getTime(), value: 30 },
  { timestamp: new Date(year, 5, 18).getTime(), value: 5 },
  { timestamp: new Date(year, 8, 9).getTime(), value: 41 },
]);
</script>

自定义范围 ​

不传 year 时,可以用 startDate / endDate 指定任意区间;两者都不传时,会从 data 的首尾时间戳推导。

一三五
2025-092025-102025-112025-122026-012026-022026-032026-04
少多
vue
<template>
  <x-heatmap :data="data" aria-label="跨年区间活跃度" />
</template>

<script setup lang="ts">
import { ref } from 'vue';

const data = ref([
  { timestamp: new Date(2026, 7, 1).getTime(), value: 8 },
  { timestamp: new Date(2026, 11, 20).getTime(), value: 26 },
  { timestamp: new Date(2027, 2, 14).getTime(), value: 31 },
]);
</script>

自定义配色 ​

activeColors 按由浅到深的顺序给出色阶,minimumColor 指定最小值(以及无数据格)的颜色。

一三五
1月2月3月4月5月6月7月8月9月10月11月12月
少多
vue
<template>
  <x-heatmap
    :year="year"
    :data="data"
    :active-colors="colors"
    :minimum-color="minimumColor"
  />
</template>

<script setup lang="ts">
import { ref } from 'vue';

const year = new Date().getFullYear();
const minimumColor = ref('#ebedf0');
const colors = ref(['#9be9a8', '#40c463', '#30a14e', '#216e39', '#0e4429']);
const data = ref([
  { timestamp: new Date(year, 0, 3).getTime(), value: 1 },
  { timestamp: new Date(year, 3, 8).getTime(), value: 60 },
]);
</script>

尺寸 ​

size 支持 small / medium / large,影响格子边长与整体密度。

一三五
1月2月3月4月5月6月7月8月9月10月11月12月
少多
一三五
1月2月3月4月5月6月7月8月9月10月11月12月
少多
一三五
1月2月3月4月5月6月7月8月9月10月11月12月
少多
vue
<template>
  <x-heatmap :year="year" :data="data" size="small" />
  <x-heatmap :year="year" :data="data" size="medium" />
  <x-heatmap :year="year" :data="data" size="large" />
</template>

<script setup lang="ts">
import { ref } from 'vue';

const year = new Date().getFullYear();
const data = ref([{ timestamp: new Date(year, 4, 20).getTime(), value: 18 }]);
</script>

标签与图例 ​

showWeekLabels / showMonthLabels / showColorIndicator 可以分别关闭星期标签、月份标签与底部图例。firstDayOfWeek 控制一周从哪天开始。

二四六
1月2月3月4月5月6月7月8月9月10月11月12月
少多
vue
<template>
  <x-heatmap :year="year" :data="data" :first-day-of-week="1" />
  <x-heatmap
    :year="year"
    :data="data"
    :show-week-labels="false"
    :show-month-labels="false"
    :show-color-indicator="false"
  />
</template>

<script setup lang="ts">
import { ref } from 'vue';

const year = new Date().getFullYear();
const data = ref([{ timestamp: new Date(year, 2, 6).getTime(), value: 9 }]);
</script>

点击事件与自定义提示 ​

点击格子会派发 cell-click;tooltip 插槽可自定义悬浮内容。

一三五
1月2月3月4月5月6月7月8月9月10月11月12月
少多
点击格子查看日期与值
vue
<template>
  <x-heatmap :year="year" :data="data" @cell-click="handleCellClick" />
  <p role="status">{{ selectedCell }}</p>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const year = new Date().getFullYear();
const data = ref([{ timestamp: new Date(year, 6, 15).getTime(), value: 22 }]);
const selectedCell = ref('点击格子查看日期与值');

const handleCellClick = (cell: { date: string; value: number | null }) => {
  selectedCell.value = `${cell.date} 的值为 ${cell.value ?? '空'}`;
};
</script>

自定义 tooltip 内容:

一三五
1月2月3月4月5月6月7月8月9月10月11月12月
少多
vue
<template>
  <x-heatmap :year="year" :data="data">
    <template #tooltip="{ date, value }">
      自定义:{{ date }} / {{ value ?? '空' }}
    </template>
  </x-heatmap>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const year = new Date().getFullYear();
const data = ref([{ timestamp: new Date(year, 8, 1).getTime(), value: 14 }]);
</script>

加载状态 ​

loading 为 true 时用 Spin 覆盖;也可以传对象透传给 Spin。

vue
<template>
  <x-heatmap :year="year" :data="data" loading />
</template>

<script setup lang="ts">
import { ref } from 'vue';

const year = new Date().getFullYear();
const data = ref([]);
</script>

按需导入 ​

ts
import { Heatmap } from 'x-next';

样式按需引入(base.css 为共享基础层,多个组件只需引入一次):

ts
import 'x-next/style/base.css';
import 'x-next/style/heatmap.css';

Props ​

属性说明类型默认值
data热力图数据HeatmapDataItem[][]
year要渲染的自然年;优先于 startDate / endDatenumber-
startDate自定义范围起始(时间戳或日期字符串)number | string-
endDate自定义范围结束(时间戳或日期字符串)number | string-
activeColors由浅到深的色阶string[]内置主色阶(5 档)
minimumColor最小值与无数据格的颜色string跟随主题
size格子尺寸'small' | 'medium' | 'large''medium'
firstDayOfWeek一周的起始日,0 为周日0 | 1 | 2 | 3 | 4 | 5 | 60
showWeekLabels是否展示星期标签booleantrue
showMonthLabels是否展示月份标签booleantrue
showColorIndicator是否展示颜色图例booleantrue
tooltip鼠标悬浮提示;传对象可配置内部浮层boolean | objecttrue
loading加载中boolean | objectfalse
ariaLabel无障碍名称:交互模式下作为网格的 aria-label,纯展示模式下让容器带 role="img"string语言包默认文案

HeatmapDataItem ​

字段说明类型
timestamp该天的任意时间戳(内部按当天零点归并)number
value该天的值;null / 省略表示无数据number | null

Events ​

事件名说明参数
cellClick点击某个日期格时触发(cell: HeatmapCell, ev: MouseEvent)

HeatmapCell 包含 timestamp / date / value / level / rowIndex / colIndex。

Slots ​

插槽名说明参数
tooltip自定义悬浮提示内容HeatmapCell & { label: string }
cell自定义格子内容HeatmapCell
indicator自定义颜色图例{ colors: string[] }
indicator-leading-text图例左端文案-
indicator-trailing-text图例右端文案-
footer网格下方的补充内容-

交互说明 ​

  • 色阶分档:有效值按 [min, max] 均分到各档;全部数据同值时统一取最高档,避免整片落到最浅色。
  • 性能:悬浮提示由整块网格共享一个节点(鼠标事件委托 + 按帧节流),不会为每个格子创建浮层实例;tooltip 关闭时改用原生 title。
  • 补齐格:为凑满整周,首尾会有日期属于区间之外的格子,它们带 x-heatmap-is-out-of-range 类并降低不透明度。
  • 月份标签:跨列数不足 3 周的月份不展示标签,以免相邻月份标注重叠。
  • 键盘导航:网格可聚焦(tooltip 开启时)。左右方向键按天移动、上下方向键按周移动,Home / End 到当周首尾,Esc 关闭提示;移动时通过 aria-live 播报「日期:数值」,鼠标悬浮不播报。
  • 无障碍结构:tooltip 开启时网格承担 role="grid"(用 aria-activedescendant 指向当前格),避免 role="img" 把整块网格对读屏隐藏;关闭提示时容器带 role="img" 作为静态图像。