如何用Chart.js基于多区域CSV数据实现可切换折线图?
更优解决方案:用映射表简化Chart.js数据集管理
核心思路
放弃手动维护索引的繁琐操作,通过国家+作物的唯一标识构建映射表,快速关联数据集与控制逻辑,同时直接生成Chart.js所需的一维数据集数组。
步骤1:解析CSV并整理结构化数据
先把所有国家的CSV解析成统一格式的结构化数据,示例用Papa Parse处理(原生FileReader也可替代):
// 解析单个国家的CSV数据 async function parseCountryCSV(filePath) { const response = await fetch(filePath); const csvText = await response.text(); const parsed = Papa.parse(csvText, { header: true }); // 提取年份和各作物产量数据 const years = parsed.data.map(row => row.year); const crops = { corn: parsed.data.map(row => parseFloat(row['Corn output (tons)'])), potato: parsed.data.map(row => parseFloat(row['Potato output (tons)'])), carrot: parsed.data.map(row => parseFloat(row['Carrot output (tons)'])) }; return { years, crops }; } // 批量解析所有国家数据 const countryData = { canada: await parseCountryCSV('canada.csv'), mexico: await parseCountryCSV('mexico.csv'), us: await parseCountryCSV('us.csv') };
步骤2:构建数据集数组与索引映射表
一次性生成Chart.js需要的数据集,同时建立indexLookup映射表(用国家_作物作为唯一键):
// 预定义作物对应颜色,方便图表区分 const cropColors = { corn: '#FFA500', potato: '#8B4513', carrot: '#FF4500' }; const chartDatasets = []; const indexLookup = {}; let currentIndex = 0; // 遍历所有国家和作物,生成Chart.js数据集 Object.entries(countryData).forEach(([country, data]) => { Object.entries(data.crops).forEach(([crop, values]) => { const key = `${country}_${crop}`; const dataset = { label: `${country.charAt(0).toUpperCase() + country.slice(1)} - ${crop.charAt(0).toUpperCase() + crop.slice(1)}`, data: data.years.map((year, idx) => ({ x: year, y: values[idx] })), borderColor: cropColors[crop], hidden: true, // 默认隐藏,后续通过复选框控制显示 fill: false }; chartDatasets.push(dataset); indexLookup[key] = currentIndex; currentIndex++; }); });
步骤3:初始化Chart.js并实现切换逻辑
用生成的chartDatasets初始化图表,通过复选框的选中状态快速控制数据集可见性:
// 初始化折线图 const ctx = document.getElementById('cropChart').getContext('2d'); const cropChart = new Chart(ctx, { type: 'line', data: { datasets: chartDatasets }, options: { scales: { x: { type: 'category', title: { display: true, text: 'Year' } }, y: { title: { display: true, text: 'Output (tons)' } } } } }); // 更新图表可见性的核心函数 function updateChartVisibility(selectedCountries, selectedCrops) { Object.keys(indexLookup).forEach(key => { const [country, crop] = key.split('_'); const isVisible = selectedCountries.includes(country) && selectedCrops.includes(crop); const index = indexLookup[key]; cropChart.setDatasetVisibility(index, isVisible); }); cropChart.update(); } // 监听国家复选框变化 document.querySelectorAll('.country-checkbox').forEach(checkbox => { checkbox.addEventListener('change', () => { const selectedCountries = Array.from(document.querySelectorAll('.country-checkbox:checked')).map(el => el.value); const selectedCrops = Array.from(document.querySelectorAll('.crop-checkbox:checked')).map(el => el.value); updateChartVisibility(selectedCountries, selectedCrops); }); }); // 监听作物复选框变化 document.querySelectorAll('.crop-checkbox').forEach(checkbox => { checkbox.addEventListener('change', () => { const selectedCountries = Array.from(document.querySelectorAll('.country-checkbox:checked')).map(el => el.value); const selectedCrops = Array.from(document.querySelectorAll('.crop-checkbox:checked')).map(el => el.value); updateChartVisibility(selectedCountries, selectedCrops); }); });
方案优势
- 无需手动维护索引:
indexLookup自动关联国家+作物组合与数据集索引,新增国家/作物时只需补充解析逻辑,不用手动调整索引。 - 逻辑解耦:数据解析、数据集生成、控制逻辑完全分离,后续维护成本低。
- 扩展性强:新增国家或作物时,仅需添加对应CSV和颜色配置,其余逻辑自动适配。
内容的提问来源于stack exchange,提问作者inbedprobably
相关产品推荐
相关产品推荐

