如何修改ECharts ThemeRiver以实现堆叠流面积图效果?
将ECharts ThemeRiver图表修改为堆叠流面积图的方案
要把现有ThemeRiver图表改成堆叠流面积图,核心是切换到直角坐标系、重构数据结构、使用带堆叠配置的折线面积图。以下是具体修改步骤和完整代码:
关键修改点
- 替换单轴(
singleAxis)为直角坐标系的xAxis和yAxis - 按电影分组重构数据,每个电影对应一个独立的折线面积系列
- 给所有系列设置相同的
stack属性实现堆叠效果 - 开启
areaStyle配置实现面积填充
修改后的完整代码
async function loadData() { try { const response = await fetch("h"); const csvText = await response.text(); const rows = csvText.split("\n").filter(row => row.trim() !== ""); const userArray = []; const headers = rows[0].split(","); for (let i = 1; i < rows.length; i++) { const regex = /(".*?"|[^",\s]+)(?=\s*,|\s*$)/g; const values = rows[i].match(regex).map(value => value.replace(/^"|"$/g, "").trim()); const releaseDate = new Date(values[1]); const releaseYear = releaseDate.getFullYear(); if (releaseYear !== 2004) continue; const dailySales = values.slice(2).map(value => { if (!value || value === "") return 0; return parseInt(value.replace(/,/g, ""), 10); }); const extendedDates = Array.from({ length: dailySales.length }, (_, index) => { const date = new Date(releaseDate); date.setDate(date.getDate() + index); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDate()).padStart(2, "0"); return `${year}/${month}/${day}`; }); const dataObject = { 영화: values[0], 개봉일: releaseDate, 개봉일차: extendedDates, 일수_매출액: dailySales }; userArray.push(dataObject); } return userArray; } catch (error) { console.error("데이터 로드 중 오류 발생:", error); } } function getISOWeek(date) { const tempDate = new Date(date); tempDate.setHours(0, 0, 0, 0); tempDate.setDate(tempDate.getDate() + 3 - ((tempDate.getDay() + 6) % 7)); const week1 = new Date(tempDate.getFullYear(), 0, 4); return Math.round(((tempDate - week1) / (7 * 24 * 60 * 60 * 1000)) + 1); } async function createChart() { try { const userArray = await loadData(); const chartDom = document.getElementById("root1"); const myChart = echarts.init(chartDom); // 按电影分组重构数据:每个电影对应一组[周数, 周销售额]数据 const seriesDataMap = new Map(); const allWeeks = new Set(); userArray.forEach(obj => { const movieName = obj.영화; const releaseWeek = getISOWeek(obj.개봉일); const dailySales = obj.일수_매출액; // 计算周销售额 const weeklySales = []; for (let j = 0; j < dailySales.length; j += 7) { const weeklyTotal = dailySales .slice(j, j + 7) .reduce((sum, value) => sum + value, 0); weeklySales.push(weeklyTotal); } // 生成当前电影的系列数据 const movieSeriesData = []; weeklySales.forEach((sales, k) => { const weekNumber = releaseWeek + k; movieSeriesData.push([weekNumber, sales]); allWeeks.add(weekNumber); }); seriesDataMap.set(movieName, movieSeriesData); }); // 转换为ECharts系列配置数组 const series = Array.from(seriesDataMap.entries()).map(([name, data]) => ({ name: name, type: 'line', stack: 'sales', // 相同stack值实现堆叠 data: data, areaStyle: {}, // 开启面积填充 label: { show: false }, emphasis: { itemStyle: { shadowBlur: 20, shadowColor: 'rgba(0, 0, 0, 0.8)' } } })); option = { xAxis: { type: 'value', name: '주차', min: Math.min(...allWeeks), max: Math.max(...allWeeks) }, yAxis: { type: 'value', name: '주간 매출액' }, dataZoom: [ { type: 'slider', show: true, start: 0, end: 100, handleSize: 8, xAxisIndex: 0 }, { type: 'inside', start: 94, end: 100, xAxisIndex: 0 } ], tooltip: { trigger: 'axis', axisPointer: { type: 'cross' } }, legend: { data: Array.from(seriesDataMap.keys()) }, series: series }; myChart.setOption(option); // 监听窗口变化,自适应图表 window.addEventListener('resize', () => { myChart.resize(); }); } catch (error) { console.error("Error creating chart:", error); } } createChart();
代码说明
- 数据重构:使用
Map按电影名称分组,将每个电影的周销售额转换为[周数, 销售额]的格式,同时收集所有周数用于坐标轴范围设置。 - 坐标系切换:移除
singleAxis,添加xAxis(周数)和yAxis(销售额),设置合适的轴类型和名称。 - 堆叠配置:所有系列设置相同的
stack: 'sales',ECharts会自动处理堆叠计算。 - 面积效果:通过
areaStyle: {}开启面积填充,实现流面积图的视觉效果。 - 交互优化:添加
legend显示电影名称,tooltip优化轴提示,同时添加窗口 resize 监听保证图表自适应。
内容的提问来源于stack exchange,提问作者홍준표
相关产品推荐
相关产品推荐

