如何为HTML表格与D3条形图添加时间间隔选择下拉菜单
实现时间间隔筛选功能的完整方案
Hey there! Let's get that time interval filter working for your tables and D3 charts. I'll break this down into actionable steps you can apply to your pages (page1, page2, page3) as needed.
1. 添加时间间隔下拉菜单到页面
首先,在每个需要筛选的页面(比如page2的<div id="page2">里,表格上方)添加这个下拉菜单:
<!-- 放在表格上方,h1之后 --> <div class="mb-3"> <label for="timeFilter">选择时间间隔:</label> <select id="timeFilter" class="form-control"> <option value="now">当前时刻(Now)</option> <option value="24h">24小时</option> <option value="48h">48小时</option> <option value="72h">72小时</option> <option value="1w">1周</option> <option value="1m">1个月</option> </select> </div>
2. 创建时间筛选工具函数
我们需要一个函数,根据选中的时间间隔过滤数据。首先把数据里的date_time字符串转成JS Date对象,然后计算和当前时间的差值:
// 放在你的script里,buildTable函数之前 function filterDataByTimeRange(rawData, timeRange) { const now = new Date(); let cutoffTime; // 根据选择的时间范围计算截止时间 switch(timeRange) { case 'now': // 当前时刻:只保留最近1分钟的数据(可根据需求调整) cutoffTime = new Date(now.getTime() - 60 * 1000); break; case '24h': cutoffTime = new Date(now.getTime() - 24 * 60 * 60 * 1000); break; case '48h': cutoffTime = new Date(now.getTime() - 48 * 60 * 60 * 1000); break; case '72h': cutoffTime = new Date(now.getTime() - 72 * 60 * 60 * 1000); break; case '1w': cutoffTime = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000); break; case '1m': cutoffTime = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000); break; default: return rawData; } // 过滤数据:只保留date_time晚于截止时间的条目 return rawData.filter(item => { const itemDate = new Date(item.date_time); return itemDate >= cutoffTime; }); }
3. 重构表格渲染函数
原来的buildTable直接拼接HTML,现在要改成先清空表格,再渲染过滤后的数据,这样切换筛选时能更新:
// 替换原来的buildTable函数 function buildTable(data) { const tableBody = document.getElementById('myTable'); // 先清空旧内容 tableBody.innerHTML = ''; data.forEach((item, index) => { // 根据不同页面的 data 结构调整(比如page1是item.data,page2是item.temperature) let measurementType, value; // 这里可以根据页面判断,或者你可以给每个页面单独写,不过统一的话可以这样: if (item.data) { // page1的结构 const key = Object.keys(item.data)[0]; measurementType = key; value = item.data[key]; } else { // page2和page3的结构,比如temperature或wind_speed const keys = Object.keys(item); measurementType = keys[2]; value = item[measurementType]; } const row = `<tr> <td>${index + 1}</td> <td>${item.date_time.substring(0, 10)}</td> <td>${item.date_time.substring(11, 19)}</td> <td>${measurementType}</td> <td>${value}</td> </tr>`; tableBody.innerHTML += row; }); }
4. 重构D3图表渲染函数(针对page2和page3)
原来的D3代码只加载一次数据,现在要改成可复用的函数,能接收过滤后的数据并重新渲染图表:
// 替换原来的D3代码,以page2为例(温度图表) let svg, g, xScale, yScale, width, height, margin; let rawChartData = []; // 存储原始图表数据 // 初始化图表容器 function initChart() { svg = d3.select("svg"); margin = 200; width = svg.attr("width") - margin; height = svg.attr("height") - margin; svg.append("text") .attr("transform", "translate(100,0)") .attr("x", 50) .attr("y", 50) .attr("font-size", "24px") .text("Temperature"); xScale = d3.scaleBand().range([0, width]).padding(0.7); yScale = d3.scaleLinear().range([height, 0]); g = svg.append("g") .attr("transform", "translate(" + 100 + "," + 100 + ")"); // 添加坐标轴标签(只需要初始化一次) g.append("g") .attr("class", "x-axis") .attr("transform", "translate(0," + height + ")") .append("text") .attr("y", height - 250) .attr("x", width - 100) .attr("text-anchor", "end") .attr("stroke", "black") .text("Time"); g.append("g") .attr("class", "y-axis") .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", "-5.1em") .attr("text-anchor", "end") .attr("stroke", "black") .text("temperature (°C)"); } // 渲染/更新图表 function renderChart(filteredData) { // 更新比例尺域 xScale.domain(filteredData.map(function(d) { return d.date_time.substring(11, 19); })); yScale.domain([0, d3.max(filteredData, function(d) { return d.temperature; })]); // 更新x轴 g.select(".x-axis") .call(d3.axisBottom(xScale)); // 更新y轴 g.select(".y-axis") .call(d3.axisLeft(yScale).tickFormat(function(d){ return d + "°C"; }).ticks(10)); // 处理条形图的enter/update/exit const bars = g.selectAll(".bar") .data(filteredData); // 移除旧的条形 bars.exit().remove(); // 添加新的条形并更新现有条形 bars.enter().append("rect") .attr("class", "bar") .merge(bars) .attr("x", function(d) { return xScale(d.date_time.substring(11, 19)); }) .attr("y", function(d) { return yScale(d.temperature); }) .attr("width", xScale.bandwidth()) .attr("height", function(d) { return height - yScale(d.temperature); }); } // 加载数据并初始化 d3.json('http://webapi19sa-1.course.tamk.cloud/v1/weather/temperature', function(error, data) { if (error) { throw error; } rawChartData = data; initChart(); // 初始渲染全部数据,或者默认选中的时间范围 renderChart(filterDataByTimeRange(rawChartData, '24h')); });
5. 绑定下拉菜单的变化事件
最后,添加事件监听,当下拉选项变化时,过滤数据并更新表格和图表:
// 放在页面的script最后,比如page2的script里 $(document).ready(function() { // 存储原始表格数据 let rawTableData = []; // 加载表格数据 $.ajax({ method:'GET', url:'url', // 替换成你的实际API地址 success:function(response){ rawTableData = response; // 初始渲染默认时间范围的数据 const initialFiltered = filterDataByTimeRange(rawTableData, '24h'); buildTable(initialFiltered); } }); // 下拉菜单变化事件 $('#timeFilter').on('change', function() { const selectedRange = $(this).val(); // 过滤表格数据并更新 const filteredTableData = filterDataByTimeRange(rawTableData, selectedRange); buildTable(filteredTableData); // 如果是有图表的页面(page2/page3),同时更新图表 if (typeof rawChartData !== 'undefined') { const filteredChartData = filterDataByTimeRange(rawChartData, selectedRange); renderChart(filteredChartData); } }); });
针对不同页面的调整
- page1:没有D3图表,所以只需要添加下拉菜单、筛选函数、重构buildTable,以及绑定下拉事件(不需要图表相关代码)。
- page3:和page2类似,只需要把图表里的
temperature换成wind_speed,调整图表标题和y轴文本即可。
注意事项
- 确保你的API返回的
date_time格式是可以被JS的new Date()正确解析的(看起来你的格式是标准ISO格式,没问题)。 - 可以根据需求调整“当前时刻”的时间范围(比如改成最近5分钟)。
- 如果数据量很大,筛选时可以考虑优化性能,但对于新手来说,当前方案足够用。
内容的提问来源于stack exchange,提问作者Arafatul Hasan
相关产品推荐
相关产品推荐

