可行但不推荐手写,因需处理跨年对齐、闰年、日期计算错误、颜色归一化及性能优化;heatmap.js需手动映射日期为x/y坐标,chart.js的heatmap插件更省心但需注意周起始和数值截断。

直接用 HTML + JavaScript 实现签到热力图,不依赖第三方库是可行的,但必须自己画格子、算颜色、处理日期映射——实际开发中,heatmap.js 或 Chart.js 插件才是省时且靠谱的选择。
为什么别手写 SVG/Canvas 热力图
签到热力图本质是「按天聚合数据 + 颜色强度映射」,看似简单,但真实场景要处理:跨年日期对齐、月份天数不一致、周末/节假日高亮需求、响应式缩放、移动端点击交互。手写容易卡在 getDay() 和 getDate() 混用导致列错位,或把 2 月 30 日当有效日期渲染出来。
- 每月起始星期几必须用
new Date(year, month, 1).getDay()算,不能硬编码 - 颜色梯度需归一化:取全部签到数的
Math.max()做分母,否则某天爆量会让其他格子全显浅色 - DOM 渲染超 365 个
<div> 元素时,Chrome 下滚动可能掉帧,得加 <code>will-change: transform用 heatmap.js 最简能跑起来的写法
heatmap.js不直接支持「日期字符串 → 像素坐标」,得自己把签到数据转成它要的{x, y, value}格式。关键在 y 轴映射:年份决定行(y),月份/日期决定列(x)。const data = [ {date: '2024-03-15', count: 3}, {date: '2024-03-16', count: 1}, // ... ]; const year = 2024; const points = data.map(d => { const dt = new Date(d.date); if (dt.getFullYear() !== year) return null; const dayOfYear = Math.floor((dt - new Date(year, 0, 0)) / (1000 * 60 * 60 * 24)); return { x: dayOfYear % 7, // 星期几(0=周日) y: Math.floor(dayOfYear / 7), // 第几周 value: d.count }; }).filter(Boolean);然后传给
h337.create({ container: document.getElementById('heatmap') })即可。注意:y值必须从 0 开始连续,断周会导致空白行。
Article To Html下载文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
用 Chart.js 的 calendar heatmap 插件更省心
官方不支持热力图,但社区插件
chartjs-chart-geo或chartjs-plugin-annotation都不贴切;真正好用的是chartjs-chart-heatmap(注意名字带-heatmap)。它原生接受时间戳数组,自动按周/月分组:const config = { type: 'heatmap', data: { datasets: [{ data: data.map(d => ({ x: d.date, // '2024-03-15' y: '2024', // 固定年份作 Y 分类 r: d.count // 半径映射数值(这里当强度用) })) }] } };缺点是:x 轴会强制按 ISO 周排序(周一为每周第一天),如果你的数据习惯用周日开头,得提前把
d.date加一天再传入;另外r值若超过 10,圆点会重叠,建议做Math.min(d.count, 8)截断。真正难的不是画出颜色块,而是让「2024-02-29」这种闰年日期不崩、让「2023-12-31」和「2024-01-01」在相邻列正确显示、让低频用户(全年只签到 3 天)的格子也能被肉眼识别——这些细节没在文档里写,只在你 console 报
NaN或空白格子时突然出现。










