如何使用Google Charts实现Ruby分组数组数据的动态折线图
我来帮你梳理下怎么把Ruby分组的数据转换成Google Charts需要的格式,毕竟Google Charts和Highcharts的数据结构确实不太一样,得先把数据规整成它能识别的结构才行。
先明确Ruby传来的数据结构
首先咱们得先对齐数据格式,假设你从Ruby端输出并传给前端的JSON解析后是这样的结构(我模拟了一组示例数据):
// 前端解析后的Ruby分组数据 const rubyGroupedData = [ ["Product A", "Product B"], // 第一个元素:产品名称数组 [ ["2024-01-01", 100], ["2024-01-02", 150], // Product A的日期+成本数据 ["2024-01-01", 80], ["2024-01-02", 120] // Product B的日期+成本数据 ] ];
这里默认第二个数组里,每个产品的日期成本数据是连续排列的(比如先放完Product A的所有数据,再放Product B的),如果你的数据不是这个顺序,后面我会补充调整方法。
方法一:手动构建DataTable(灵活适配各种数据情况)
如果你的数据存在日期不统一、部分产品某日期无数据的情况,用这个方法更稳妥:
// 1. 提取基础数据 const productNames = rubyGroupedData[0]; const rawDataPoints = rubyGroupedData[1]; // 2. 按产品拆分原始数据 const pointsPerProduct = rawDataPoints.length / productNames.length; const productData = productNames.map((name, index) => { // 计算当前产品数据的起止索引 const startIdx = index * pointsPerProduct; const endIdx = startIdx + pointsPerProduct; return { name: name, data: rawDataPoints.slice(startIdx, endIdx).map(point => ({ date: new Date(point[0]), // 转成Google Charts要求的Date对象 cost: point[1] })) }; }); // 3. 收集所有唯一日期并排序 const allDates = [...new Set(productData.flatMap(p => p.data.map(d => d.date.toISOString())))] .map(str => new Date(str)) .sort((a, b) => a - b); // 按时间顺序排序 // 4. 构建DataTable const dataTable = new google.visualization.DataTable(); // 添加X轴的日期列 dataTable.addColumn('date', 'Date'); // 为每个产品添加Y轴成本列 productNames.forEach(name => dataTable.addColumn('number', name)); // 5. 填充每一行数据(按日期匹配各产品的成本) allDates.forEach(date => { const row = [date]; productData.forEach(product => { // 找到当前产品在该日期的成本,无数据则设为null(折线图会自动跳过) const match = product.data.find(d => d.date.toISOString() === date.toISOString()); row.push(match ? match.cost : null); }); dataTable.addRow(row); });
方法二:用ArrayDataTable(适合规整数据)
如果你的数据非常规整——每个产品的日期完全一致、顺序也相同,那可以用更简洁的arrayToDataTable方法:
// 1. 提取基础数据 const productNames = rubyGroupedData[0]; const rawDataPoints = rubyGroupedData[1]; // 2. 按产品拆分数据 const pointsPerProduct = rawDataPoints.length / productNames.length; const productDataArrays = productNames.map((_, index) => { const startIdx = index * pointsPerProduct; return rawDataPoints.slice(startIdx, startIdx + pointsPerProduct); }); // 3. 构造ArrayDataTable需要的二维数组 // 表头:[日期列, 产品1列, 产品2列...] const headers = [['date', 'Date'], ...productNames.map(name => ['number', name])]; // 行数据:按日期分组,每行对应一个日期下所有产品的成本 const rows = []; for (let i = 0; i < pointsPerProduct; i++) { const date = new Date(productDataArrays[0][i][0]); const row = [date]; productDataArrays.forEach(product => row.push(product[i][1])); rows.push(row); } // 4. 创建ArrayDataTable const dataTable = google.visualization.arrayToDataTable([headers, ...rows]);
最后绘制折线图
不管用哪种方法得到dataTable,绘制折线图的代码都是通用的:
// 先加载Google Charts库(记得放在HTML的<head>里) google.charts.load('current', {'packages':['corechart']}); google.charts.setOnLoadCallback(drawChart); function drawChart() { // 上面的代码生成dataTable... const options = { title: '产品成本趋势', hAxis: {title: '日期', format: 'yyyy-MM-dd'}, vAxis: {title: '成本'}, // 可以自定义每个产品系列的样式 series: productNames.map((name, idx) => ({ name: name, color: ['#2196F3', '#F44336'][idx] })), legend: {position: 'bottom'} }; // 渲染图表到指定DOM元素 const chart = new google.visualization.LineChart(document.getElementById('chart_div')); chart.draw(dataTable, options); }
特殊情况处理:数据混排的情况
如果Ruby传来的第二个数组是按日期混排的(比如先放所有产品1号的数据,再放所有产品2号的数据),那可以用Map来重新整理数据:
const dataMap = new Map(); rawDataPoints.forEach((point, idx) => { const productIdx = idx % productNames.length; const productName = productNames[productIdx]; const date = new Date(point[0]); const cost = point[1]; if (!dataMap.has(date)) dataMap.set(date, new Map()); dataMap.get(date).set(productName, cost); }); // 之后再把dataMap转成DataTable的行数据即可,逻辑和方法一类似
内容的提问来源于stack exchange,提问作者yash041
相关产品推荐
相关产品推荐

