上一篇
d3js绘制日历
- 行业动态
- 2025-04-14
- 7
D3.js可通过数据绑定动态生成日历视图,利用SVG绘制日期格子,结合时间尺度布局月份,支持交互高亮与数据展示,适用于可视化日程、习惯追踪等场景,灵活自定义样式与事件响应。
要在网页上使用D3.js创建日历可视化,可以通过以下步骤实现一个交互式日历,本教程以2024年9月为例,完整代码可直接嵌入网页使用。
实现原理
日历本质上是二维日期矩阵的可视化映射,通过D3的布局算法,我们将日期数据转换为:
- 按周分组的日期矩阵
- 日期与坐标的对应关系
- 可视化元素的样式绑定
核心代码实现
<div id="calendar"></div> <script src="https://d3js.org/d3.v7.min.js"></script> <script> // 基础配置 const width = 800; const cellSize = 80; const weekDays = ["日", "一", "二", "三", "四", "五", "六"]; // 创建SVG画布 const svg = d3.select("#calendar") .append("svg") .attr("width", width) .attr("height", cellSize * 7); // 生成日期数据集 const startDate = new Date(2024, 8, 1); // 2024年9月1日 const endDate = new Date(2024, 9, 0); // 获取9月最后一天 const dates = d3.timeDays(startDate, endDate); // 创建日历布局 const calendarLayout = d3.timeWeek .range(startDate, endDate) .map(week => d3.timeDay.range(week, d3.timeDay.offset(week, 7))); // 绘制日历格子 svg.selectAll(".week") .data(calendarLayout) .enter().append("g") .attr("transform", (d,i) => `translate(0,${i * cellSize})`) .selectAll(".day") .data(d => d) .enter().append("rect") .attr("class", "day-cell") .attr("x", (d,i) => i * cellSize) .attr("width", cellSize - 2) .attr("height", cellSize - 2) .style("fill", d => d.getMonth() === 8 ? "#fff" : "#f5f5f5") // 非本月日期 .style("stroke", "#eee"); // 添加日期文字 svg.selectAll(".day-text") .data(dates) .enter().append("text") .attr("x", (d,i) => { const week = Math.floor(i / 7); return (i % 7) * cellSize + 10; }) .attr("y", (d,i) => Math.floor(i / 7) * cellSize + 30) .text(d => d.getDate()) .style("font-size", "24px") .style("fill", d => d.getDay() === 0 ? "red" : "#333"); // 添加周次标识 svg.append("g") .selectAll("text") .data(weekDays) .enter().append("text") .attr("x", (d,i) => i * cellSize + 30) .attr("y", 20) .text(d => d) .style("font-weight", "bold"); </script> <style> .day-cell:hover { fill: #e3f2fd !important; cursor: pointer; } text { font-family: 'Arial', sans-serif; user-select: none; } </style>
扩展功能建议
数据绑定:通过
.datum()
方法关联每日数据.day-cell.datum(function(d) { return { date: d, value: Math.random() * 100 // 示例数据 }; })
交互功能:添加点击事件
.on("click", function(event, d) { d3.select(this).style("fill", "#b3e5fc"); console.log("选中日期:", d.toLocaleDateString()); })
热力效果:根据数据值染色
.style("fill", d => { const value = d.value || 0; return d3.interpolateBlues(value/100); })
技术要点
- 时间计算:使用
d3.timeDays
生成完整日期序列 - 矩阵布局:通过
d3.timeWeek
创建周次分组 - 坐标映射:通过(i % 7)计算横向坐标,Math.floor(i/7)计算纵向坐标
- 性能优化:使用虚拟DOM进行批量元素操作
适配调整建议
- 响应式布局:添加viewBox属性实现自适应
.attr("viewBox", `0 0 ${width} ${cellSize*6}`)
- 国际化:使用
d3.timeFormat
适配不同日期格式 - 数据加载:结合
d3.json()
实现动态数据绑定
参考文献:
- D3官方日历示例 (https://observablehq.com/@d3/calendar)
- MDN Date对象文档 (https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date)
- 《Interactive Data Visualization for the Web》第二版,第7章时间数据处理