LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

使用 HTML + JavaScript 实现活跃度热力图(附完整代码)

admin
2026年1月6日 11:19 本文热度 329
活跃度热力图能够直观地展示用户在一段时间内的活动频率,通过颜色深浅的变化让用户快速识别出活跃的高峰期和低谷期。这种可视化方式在 GitHub 个人主页上广为人知,它将复杂的活动数据转化为易于理解的视觉表现,帮助用户快速把握自己的行为模式。热力图通过颜色深浅直观反映数据密度,让用户一眼就能识别出活跃的高峰期和低谷期。本文将介绍如何使用 HTML、CSS 和 JavaScript 实现活跃度热力图。

效果演示

热力图以网格形式展示过去一年的活跃度数据。每个小方块代表一天的活跃情况,颜色越深表示活跃度越高。鼠标悬停在方块上时会显示具体日期和活跃次数,底部的图例显示了不同颜色对应的活跃度等级。顶部有月份标记帮助用户定位时间,左侧有星期标签便于识别星期几。

页面结构

页面主要包括热力图网格(core)、图例(legend)和提示框(tip)三个部分。
<div id="core">  <div id="week-label"></div>  <div id="grid"></div></div>
<div id="legend">  <span style="margin-right:8px"></span>  <div class="cell lv0"></div>  <div class="cell lv1"></div>  <div class="cell lv2"></div>  <div class="cell lv3"></div>  <div class="cell lv4"></div>  <span style="margin-left:8px"></span></div>
<div id="tip"></div>

核心功能实现

数据按周分组

groupByWeeks 函数将一年的数据按周进行分组,使数据能够按星期对齐显示。这个函数处理了起始日期可能不在周一开始的情况,通过在第一周前面添加空值来对齐。
function groupByWeeks(data) {  const weeks = [];  let week = new Array(7).fill(null);  const start = data[0].date;  const mon = (start.getDay() + 6) % 7;  // 填充第一周  for (let i = 0; i < mon; i++) {    week[i] = null;  }  for (let i = mon; i < 7; i++) {    week[i] = data.shift();  }  weeks.push(week);  // 处理剩余周  while (data.length) {    week = new Array(7);    for (let i = 0; i < 7 && data.length; i++) {      week[i] = data.shift();    }    if (data.length === 0 && week.length < 7) {      for (let i = week.length; i < 7; i++) {        week[i] = null;      }    }    weeks.push(week);  }  return weeks;}

渲染热力图网格

renderGrid 函数根据分组后的数据渲染网格,为每个日期单元格分配对应的颜色等级。这个函数还处理了月份标记的显示,每到每月15号就在对应单元格上显示月份名称。
function renderGrid(weeks) {  const monthNames = ['一月','二月','三月','四月','五月','六月','七月','八月','九月','十月','十一月','十二月'];  const grid = document.getElementById('grid');  weeks.forEach(wk => {    wk.forEach(day => {      const cell = document.createElement('div');      cell.className = 'cell lv0';      if (day) {        cell.className = 'cell lv' + day.level;        cell.dataset.date = day.date.toLocaleDateString('zh-CN');        cell.dataset.count = day.count;      } else {        cell.style.visibility = 'hidden';      }      // 检查是否是每月15号,添加月份标记      if (day && day.date.getDate() === 15) {        const monthMarker = document.createElement('div');        monthMarker.className = 'month-marker';        monthMarker.textContent = monthNames[day.date.getMonth()];        cell.appendChild(monthMarker);      }      grid.appendChild(cell);    });  });}

实现交互提示功能

setupTooltip 函数为热力图添加鼠标悬停提示功能,显示具体日期和活跃次数。同时处理提示框的位置,确保其始终在可视区域内显示。
function setupTooltip() {  const grid = document.getElementById('grid');  const tip = document.getElementById('tip');  grid.addEventListener('mouseover'e => {    if (!e.target.dataset.datereturn;    tip.textContent = `${e.target.dataset.date} 活跃 ${e.target.dataset.count} 次`;    tip.style.display = 'block';  });  grid.addEventListener('mousemove'e => {    const pad = 6;    let x = e.pageX + pad;    let y = e.pageY - tip.offsetHeight - pad;    if (x + tip.offsetWidth > window.scrollX + window.innerWidth) x = e.pageX - tip.offsetWidth - pad;    if (y < window.scrollY) y = e.pageY + pad;    tip.style.left = x + 'px';    tip.style.top = y + 'px';  });  grid.addEventListener('mouseout'() => tip.style.display = 'none');}

扩展建议

  • 添加数据加载功能,支持从 API 获取真实活跃数据

  • 实现颜色主题切换,提供多种配色方案供用户选择

  • 增加时间范围选择,支持查看不同时间段的活跃情况

  • 添加导出功能,允许用户保存热力图到本地

完整代码

git地址:https://gitee.com/ironpro/hjdemo/blob/master/heatmap/index.html
<!DOCTYPE html><html lang="zh-CN"><head>  <meta charset="utf-8">  <meta name="viewport" content="width=device-width, initial-scale=1.0" />  <title>活跃度热力图</title>  <style>      * {          margin0;          padding0;          box-sizing: border-box;      }      body {          background#f5f5f5;          padding20px;          min-height100vh;          color#333;      }      .container {          background: white;          padding20px;          width1200px;          margin0 auto;          box-shadow0 4px 14px rgba(0000.08);      }      h1 {          color#2c3e50;          font-size22px;          margin-bottom25px;          text-align: center;          border-bottom1px solid #eee;          padding-bottom15px;      }      #cal-wrap {          margin0 auto;          width: max-content;          position: relative;          padding-top30px;      }      #core {          display: flex;          align-items: flex-start;      }      #week-label {          display: grid;          grid-template-rowsrepeat(716px);          gap3px;          margin-right8px;          font-size11px;          color#666666;          text-align: right;      }      #week-label span {          display: flex;          align-items: center;          height16px;          justify-content: flex-end;      }      #grid {          display: grid;          grid-template-rowsrepeat(716px);          grid-auto-flow: column;          gap3px;          position: relative;      }      .cell {          width16px;          height16px;          cursor: pointer;      }      .lv0 {background#ebedf0;}      .lv1 {background#9be9a8;}      .lv2 {background#40c463;}      .lv3 {background#30a14e;}      .lv4 {background#216e39;}      #legend {          margin-top20px;          display: flex;          align-items: center;          font-size14px;          color#666666;          justify-content: end;      }      #legend .cell {          margin0 1px;      }      #tip {          position: absolute;          backgroundrgba(0000.95);          color#fff;          font-size13px;          padding8px 14px;          white-space: nowrap;          pointer-events: none;          display: none;          z-index999;          font-weight400;          box-shadow0 4px 8px rgba(0000.15);      }      .month-marker {          position: absolute;          top: -25px;          font-size14px;          color#666666;          transformtranslateX(-50%);          white-space: nowrap;          font-weight500;          margin-left14px;      }  </style></head><body><div class="container">  <h1>活跃度热力图</h1>  <div id="cal-wrap">    <div id="core">      <div id="week-label"></div>      <div id="grid"></div>    </div>    <div id="legend">      <span style="margin-right:8px"></span>      <div class="cell lv0"></div>      <div class="cell lv1"></div>      <div class="cell lv2"></div>      <div class="cell lv3"></div>      <div class="cell lv4"></div>      <span style="margin-left:8px"></span>    </div>  </div></div>
<div id="tip"></div>
<script>  // 生成一年数据  function generateYearData() {    const today = new Date();    const start = new Date(today);    start.setDate(today.getDate() - 365);    const data = [];    for (let d = new Date(start); d <= today; d.setDate(d.getDate() + 1)) {      const count = Math.floor(Math.random() * 25);      let level = 0;      if (count === 0) level = 0;      else if (count < 5) level = 1;      else if (count < 10) level = 2;      else if (count < 20) level = 3;      else level = 4;      data.push({        datenew Date(d),        count,        level      });    }    return data;  }  // 按周分组  function groupByWeeks(data) {    const weeks = [];    let week = new Array(7).fill(null);    const start = data[0].date;    const mon = (start.getDay() + 6) % 7;    // 填充第一周    for (let i = 0; i < mon; i++) {      week[i] = null;    }    for (let i = mon; i < 7; i++) {      week[i] = data.shift();    }    weeks.push(week);    // 处理剩余周    while (data.length) {      week = new Array(7);      for (let i = 0; i < 7 && data.length; i++) {        week[i] = data.shift();      }      if (data.length === 0 && week.length < 7) {        for (let i = week.length; i < 7; i++) {          week[i] = null;        }      }      weeks.push(week);    }    return weeks;  }  // 渲染星期标签  function renderWeekLabels() {    const weekLabel = document.getElementById('week-label');    const weekDays = ['周一','周二','周三','周四','周五','周六','周日'];    weekDays.forEach((day, i) => {      const s = document.createElement('span');      if (i % 2 === 0) s.textContent = day;      weekLabel.appendChild(s);    });  }  // 渲染热力图网格  function renderGrid(weeks) {    const monthNames = ['一月','二月','三月','四月','五月','六月','七月','八月','九月','十月','十一月','十二月'];    const grid = document.getElementById('grid');    weeks.forEach(wk => {      wk.forEach(day => {        const cell = document.createElement('div');        cell.className = 'cell lv0';        if (day) {          cell.className = 'cell lv' + day.level;          cell.dataset.date = day.date.toLocaleDateString('zh-CN');          cell.dataset.count = day.count;        } else {          cell.style.visibility = 'hidden';        }        // 检查是否是每月15号,添加月份标记        if (day && day.date.getDate() === 15) {          const monthMarker = document.createElement('div');          monthMarker.className = 'month-marker';          monthMarker.textContent = monthNames[day.date.getMonth()];          cell.appendChild(monthMarker);        }        grid.appendChild(cell);      });    });  }  // 交互提示  function setupTooltip() {    const grid = document.getElementById('grid');    const tip = document.getElementById('tip');    grid.addEventListener('mouseover'e => {      if (!e.target.dataset.datereturn;      tip.textContent = `${e.target.dataset.date} 活跃 ${e.target.dataset.count} 次`;      tip.style.display = 'block';    });    grid.addEventListener('mousemove'e => {      const pad = 6;      let x = e.pageX + pad;      let y = e.pageY - tip.offsetHeight - pad;      if (x + tip.offsetWidth > window.scrollX + window.innerWidth) x = e.pageX - tip.offsetWidth - pad;      if (y < window.scrollY) y = e.pageY + pad;      tip.style.left = x + 'px';      tip.style.top = y + 'px';    });    grid.addEventListener('mouseout'() => tip.style.display = 'none');  }  // 初始化热力图  function initHeatmap() {    const data = generateYearData();    const weeks = groupByWeeks(data);    renderWeekLabels();    renderGrid(weeks);    setupTooltip();  }  initHeatmap()</script></body></html>


阅读原文:原文链接


该文章在 2026/1/6 18:30:32 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved