如何使用Chart.js实现联动图表(饼图筛选折线图数据)
实现Chart.js饼图与折线图的联动筛选
没问题,我直接给你一个可以跑的实用案例,完全适配你的需求——点击饼图的类别扇区,折线图就只展示对应类别下的商品价格走势。
核心思路
- 先把原始数据做分组整理,方便后续快速筛选
- 初始化饼图展示所有商品类别
- 初始化折线图默认显示全量数据
- 给饼图绑定点击事件,触发时过滤对应类别的数据,更新折线图
完整代码示例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Chart联动示例</title> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> </head> <body> <div style="display: flex; gap: 20px; padding: 20px;"> <div style="width: 400px;"> <h3>商品类别筛选</h3> <canvas id="categoryPieChart"></canvas> </div> <div style="width: 600px;"> <h3>价格走势</h3> <canvas id="priceLineChart"></canvas> </div> </div> <script> // 你的原始数据 const rawData = [ {"date": "06/01/2023 16:45", "item": "Apple", "cat": "Fruit", "price": "9.00"}, {"date": "06/01/2023 16:45", "item": "Orange", "cat": "Fruit", "price": "8.00"}, {"date": "06/01/2023 16:45", "item": "Pear", "cat": "Fruit", "price": "7.00"}, {"date": "06/01/2023 16:45", "item": "Water", "cat": "Drink", "price": "2.00"}, {"date": "06/01/2023 16:45", "item": "Soda", "cat": "Drink", "price": "3.00"}, {"date": "07/01/2023 16:45", "item": "Apple", "cat": "Fruit", "price": "9.50"}, {"date": "07/01/2023 16:45", "item": "Orange", "cat": "Fruit", "price": "8.50"}, {"date": "07/01/2023 16:45", "item": "Pear", "cat": "Fruit", "price": "7.50"}, {"date": "07/01/2023 16:45", "item": "Water", "cat": "Drink", "price": "2.50"}, {"date": "07/01/2023 16:45", "item": "Soda", "cat": "Drink", "price": "3.50"} ]; // 第一步:预处理数据,方便后续使用 // 1. 提取所有唯一日期并排序 const allDates = [...new Set(rawData.map(item => item.date))].sort((a, b) => new Date(a) - new Date(b)); // 2. 按类别分组数据 const groupedByCategory = rawData.reduce((acc, item) => { if (!acc[item.cat]) acc[item.cat] = []; acc[item.cat].push(item); return acc; }, {}); // 3. 按商品分组,整理每个商品的价格时间序列 const groupedByItem = rawData.reduce((acc, item) => { if (!acc[item.item]) { acc[item.item] = { cat: item.cat, prices: allDates.map(date => { const match = rawData.find(d => d.item === item.item && d.date === date); return match ? parseFloat(match.price) : null; }) }; } return acc; }, {}); // 第二步:初始化饼图 const pieCtx = document.getElementById('categoryPieChart').getContext('2d'); const pieChart = new Chart(pieCtx, { type: 'pie', data: { labels: Object.keys(groupedByCategory), datasets: [{ label: '商品数量', data: Object.values(groupedByCategory).map(items => items.length), backgroundColor: ['#FF6384', '#36A2EB'], hoverOffset: 4 }] }, options: { responsive: true, // 关键:饼图点击事件 onClick: (e, elements) => { if (elements.length === 0) return; // 获取点击的类别 const clickedCategory = pieChart.data.labels[elements[0].index]; // 更新折线图数据 updateLineChart(clickedCategory); } } }); // 第三步:初始化折线图(默认显示全量数据) const lineCtx = document.getElementById('priceLineChart').getContext('2d'); let lineChart = new Chart(lineCtx, { type: 'line', data: { labels: allDates, datasets: Object.entries(groupedByItem).map(([itemName, data], index) => ({ label: itemName, data: data.prices, borderColor: index % 2 === 0 ? '#FF6384' : '#36A2EB', fill: false, tension: 0.1 })) }, options: { responsive: true, scales: { y: { beginAtZero: true, title: { display: true, text: '价格' } }, x: { title: { display: true, text: '日期' } } } } }); // 第四步:定义折线图更新函数 function updateLineChart(selectedCategory) { // 筛选出对应类别的商品 const filteredItems = Object.entries(groupedByItem).filter(([_, data]) => data.cat === selectedCategory); // 生成新的数据集 const newDatasets = filteredItems.map(([itemName, data], index) => ({ label: itemName, data: data.prices, borderColor: selectedCategory === 'Fruit' ? '#FF6384' : '#36A2EB', fill: false, tension: 0.1 })); // 更新折线图 lineChart.data.datasets = newDatasets; lineChart.update(); } </script> </body> </html>
关键细节说明
- 数据预处理:提前把数据按类别、商品分组,避免每次点击都重新遍历全量数据,提升性能
- 饼图点击事件:通过
onClick回调获取点击的扇区索引,进而拿到对应的类别 - 折线图更新:调用
chart.update()方法实现数据刷新,这是Chart.js更新图表的标准方式 - 样式适配:给不同类别的折线设置了不同颜色,方便区分
你可以直接把这段代码保存成HTML文件打开就能看到效果,点击饼图的「Fruit」或「Drink」,折线图就会自动切换对应类别的商品数据啦。
内容的提问来源于stack exchange,提问作者douglaslps
相关产品推荐
相关产品推荐

