Node.js项目中如何调整数据适配HighCharts堆叠柱形图需求
哈哈,我之前刚好做过类似的HighCharts堆叠柱场景,你已经搞定了取数和基础渲染,现在就差把数据调整成适配堆叠需求的结构对吧?给你一步步拆解:
步骤1:先把数据库原始数据理清楚
首先假设你从数据库拿到的是包含日期、小时、下雨状态的数组,第一步要做的是按日期分组,并且补全每个日期的0-23小时(避免有些小时没数据导致图表缺失):
// 示例原始数据(你从数据库查询回来的结构大概是这样) const dbData = [ { date: '2024-05-01', hour: 7, isRainy: true }, { date: '2024-05-01', hour: 8, isRainy: true }, { date: '2024-05-01', hour: 9, isRainy: false }, { date: '2024-05-01', hour: 15, isRainy: true }, { date: '2024-05-02', hour: 10, isRainy: true }, { date: '2024-05-02', hour: 11, isRainy: true }, { date: '2024-05-02', hour: 12, isRainy: true }, ]; // 按日期分组,同时补全24小时的默认状态 const groupedData = {}; dbData.forEach(item => { if (!groupedData[item.date]) { // 初始化该日期的24小时,默认非下雨 groupedData[item.date] = Array.from({ length: 24 }, (_, i) => ({ hour: i, isRainy: false })); } // 更新对应小时的下雨状态 groupedData[item.date][item.hour].isRainy = item.isRainy; });
步骤2:转换成HighCharts需要的堆叠数据结构
这里分两种情况,看你的具体需求:
情况1:只区分“下雨/非下雨”两类堆叠
这种是最常见的,每个日期的柱形由“下雨小时数”和“非下雨小时数”堆叠而成:
// 提取所有日期作为X轴的类别 const xAxisCategories = Object.keys(groupedData); // 构建下雨时段的系列数据:每个日期对应下雨的总小时数 const rainySeriesData = xAxisCategories.map(date => { return groupedData[date].filter(hourItem => hourItem.isRainy).length; }); // 构建非下雨时段的系列数据:24减去下雨小时数 const nonRainySeriesData = xAxisCategories.map(date => { return 24 - rainySeriesData[xAxisCategories.indexOf(date)]; }); // 最终的系列数组 const series = [ { name: '非下雨时段', data: nonRainySeriesData, color: '#e0e0e0', // 灰色 stack: 'hours' // 关键:同一个stack名称才会堆叠 }, { name: '下雨时段', data: rainySeriesData, color: '#1f77b4', // 蓝色 stack: 'hours' } ];
情况2:按连续下雨时段拆分堆叠(比如一天有两个下雨时段就显示两个蓝色块)
如果需要更精细地展示每个连续的下雨时段,就得先合并连续的小时段,再为每个时段创建系列:
// 辅助函数:把连续的下雨小时合并成时段 function getContinuousRainyPeriods(hourList) { const periods = []; let currentStart = null; hourList.forEach((item, index) => { if (item.isRainy) { if (currentStart === null) currentStart = item.hour; // 检查下一个小时是否非下雨,或者是最后一个小时 if (index === hourList.length - 1 || !hourList[index + 1].isRainy) { periods.push({ start: currentStart, end: item.hour, duration: item.hour - currentStart + 1 }); currentStart = null; } } }); return periods; } // 提取日期列表 const xAxisCategories = Object.keys(groupedData); // 初始化系列:先加一个非下雨的基础层 const series = [{ name: '非下雨时段', data: xAxisCategories.map(() => 24), color: '#e0e0e0', stack: 'hours' }]; // 为每个连续下雨时段创建系列 xAxisCategories.forEach(date => { const periods = getContinuousRainyPeriods(groupedData[date]); periods.forEach((period) => { // 避免重复创建相同时段的系列 let existingSeries = series.find(s => s.name === `下雨时段 ${period.start}-${period.end}`); if (!existingSeries) { existingSeries = { name: `下雨时段 ${period.start}-${period.end}`, data: new Array(xAxisCategories.length).fill(0), color: '#1f77b4', stack: 'hours' }; series.push(existingSeries); } // 填充当前日期的该时段时长 existingSeries.data[xAxisCategories.indexOf(date)] = period.duration; }); });
步骤3:在Handlebars模板中渲染图表
在Node.js端把整理好的xAxisCategories和series转换成JSON,然后在Handlebars模板里无转义输出(用{{{}}}避免转义问题):
<!-- 你的Handlebars模板 --> <div id="rain-chart" style="width: 100%; height: 400px;"></div> <script> // 从模板接收后端传递的数据 const chartConfig = { xAxisCategories: {{{JSON.stringify(xAxisCategories)}}}, series: {{{JSON.stringify(series)}}} }; // 初始化HighCharts Highcharts.chart('rain-chart', { chart: { type: 'column' }, title: { text: '每日下雨时段堆叠柱形图' }, xAxis: { categories: chartConfig.xAxisCategories, title: { text: '日期' } }, yAxis: { min: 0, max: 24, title: { text: '小时数' }, stackLabels: { enabled: true, fontWeight: 'bold' } }, tooltip: { headerFormat: '<b>{point.x}</b><br/>', pointFormat: '{series.name}: {point.y} 小时' }, plotOptions: { column: { stacking: 'normal', dataLabels: { enabled: true, color: 'white' } } }, series: chartConfig.series }); </script>
注意: 如果你用的是Express+Handlebars,记得在路由里把xAxisCategories和series作为模板变量传递过去。
内容的提问来源于stack exchange,提问作者FoxHound
相关产品推荐
相关产品推荐

