React+Chart.js实现多产品每日价格折线图的展示调整需求
React + Chart.js 产品每日价格折线图调整方案
1. 数据预处理(核心修正步骤)
原始数据集是按单条记录存储的产品日期价格数据,需先按产品名称分组,同时提取并排序所有日期(确保从旧到新):
// 假设传入组件的原始数据集为props.data const groupedData = data.reduce((acc, item) => { if (!acc[item.product_name]) { acc[item.product_name] = []; } acc[item.product_name].push({ date: item.date, whole_price: item.whole_price, retail_price: item.retail_price }); return acc; }, {}); // 提取唯一日期并按时间排序(旧→新) const sortedDates = [...new Set(data.map(item => item.date))].sort((a, b) => new Date(a) - new Date(b));
2. 图表配置修正
X轴日期顺序控制
使用Chart.js的TimeScale轴保证日期按时间顺序展示,需引入适配库:
options: { scales: { x: { type: 'time', time: { unit: 'day', displayFormats: { day: 'yyyy-MM-dd' } }, title: { display: true, text: '日期' } }, y: { title: { display: true, text: '价格' }, beginAtZero: false } }, legend: { position: 'top', // 图例直接显示产品名称(对应数据集的label) labels: { usePointStyle: true } } }
产品数据集生成
根据选中的价格类型,为每个产品生成对应的折线数据,缺失日期用null填充保证折线连续:
const generateDatasets = (priceType) => { return Object.entries(groupedData).map(([productName, prices], index) => { const dataPoints = sortedDates.map(date => { const match = prices.find(p => p.date === date); return match ? match[priceType] : null; }); // 自定义产品配色(可按需扩展) const colors = ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF']; return { label: productName, data: dataPoints, borderColor: colors[index % colors.length], backgroundColor: `${colors[index % colors.length]}20`, fill: false, tension: 0.1 }; }); };
3. 批发/零售价切换功能
用React状态管理选中的价格类型,切换时自动更新图表数据:
const [selectedPriceType, setSelectedPriceType] = useState('whole_price'); // 切换按钮UI <div style={{ marginBottom: '1rem' }}> <button onClick={() => setSelectedPriceType('whole_price')} style={{ padding: '0.5rem 1rem', marginRight: '0.5rem', border: 'none', borderRadius: '4px', cursor: 'pointer', backgroundColor: selectedPriceType === 'whole_price' ? '#36A2EB' : '#e0e0e0', color: selectedPriceType === 'whole_price' ? '#fff' : '#000' }} > 批发价 </button> <button onClick={() => setSelectedPriceType('retail_price')} style={{ padding: '0.5rem 1rem', border: 'none', borderRadius: '4px', cursor: 'pointer', backgroundColor: selectedPriceType === 'retail_price' ? '#FF6384' : '#e0e0e0', color: selectedPriceType === 'retail_price' ? '#fff' : '#000' }} > 零售价 </button> </div>
4. 完整可运行组件代码
import React, { useState, useEffect } from 'react'; import { Line } from 'react-chartjs-2'; import { Chart as ChartJS, LinearScale, PointElement, LineElement, Title, Tooltip, Legend, TimeScale } from 'chart.js'; import 'chartjs-adapter-date-fns'; // 时间轴适配依赖 // 注册Chart.js所需组件 ChartJS.register(LinearScale, PointElement, LineElement, Title, Tooltip, Legend, TimeScale); const PriceChart = ({ data }) => { const [selectedPriceType, setSelectedPriceType] = useState('whole_price'); const [chartData, setChartData] = useState({ datasets: [] }); useEffect(() => { if (!data?.length) return; // 按产品分组数据 const groupedData = data.reduce((acc, item) => { acc[item.product_name] ??= []; acc[item.product_name].push(item); return acc; }, {}); // 排序日期 const sortedDates = [...new Set(data.map(i => i.date))].sort((a, b) => new Date(a) - new Date(b)); // 生成对应价格类型的数据集 const datasets = Object.entries(groupedData).map(([name, prices], idx) => { const colors = ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF']; return { label: name, data: sortedDates.map(date => prices.find(p => p.date === date)?.[selectedPriceType] || null), borderColor: colors[idx % colors.length], backgroundColor: `${colors[idx % colors.length]}20`, fill: false, tension: 0.1 }; }); setChartData({ labels: sortedDates, datasets }); }, [data, selectedPriceType]); const chartOptions = { responsive: true, scales: { x: { type: 'time', time: { unit: 'day', displayFormats: { day: 'yyyy-MM-dd' } }, title: { display: true, text: '日期' } }, y: { title: { display: true, text: '价格' }, beginAtZero: false } }, tooltip: { mode: 'index', intersect: false } }; return ( <div> <div style={{ marginBottom: '1rem' }}> <button onClick={() => setSelectedPriceType('whole_price')} style={{ padding: '0.5rem 1rem', marginRight: '0.5rem', border: 'none', borderRadius: '4px', cursor: 'pointer', backgroundColor: selectedPriceType === 'whole_price' ? '#36A2EB' : '#e0e0e0', color: selectedPriceType === 'whole_price' ? '#fff' : '#000' }} > 批发价 </button> <button onClick={() => setSelectedPriceType('retail_price')} style={{ padding: '0.5rem 1rem', border: 'none', borderRadius: '4px', cursor: 'pointer', backgroundColor: selectedPriceType === 'retail_price' ? '#FF6384' : '#e0e0e0', color: selectedPriceType === 'retail_price' ? '#fff' : '#000' }} > 零售价 </button> </div> <Line data={chartData} options={chartOptions} /> </div> ); }; export default PriceChart;
依赖安装提示
确保安装必要依赖包:
npm install chart.js react-chartjs-2 chartjs-adapter-date-fns
内容的提问来源于stack exchange,提问作者bedrani sidali
相关产品推荐
相关产品推荐

