You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Chart.js基于历史价格数据生成近12个月价格曲线图表?

如何用Chart.js生成近12个月的价格走势折线图

我来一步步帮你搞定这个需求,核心是把你的历史价格数据和生成的12个月列表做匹配,再配置Chart.js的坐标轴和数据集。下面是完整的实现方案:


第一步:准备工作

首先确保你已经引入了两个必要的库:

  • moment.js(用来处理日期格式转换)
  • Chart.js(用来生成图表)

你可以用CDN引入,或者本地导入:

<script src="https://cdn.jsdelivr.net/npm/moment@2.29.4/moment.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.8/dist/chart.umd.min.js"></script>

同时在HTML中添加一个canvas容器,用来渲染图表:

<canvas id="priceChart" width="400" height="200"></canvas>

第二步:处理数据匹配

你已经有了生成过去12个月的函数,但需要把原始价格数据和这些月份对应起来。这里写一个处理函数,把零散的历史数据映射到每个月份上:

function getPreviousMonths() { 
  var months = []; 
  for (i = 0; i < 12; i++) { 
    var month = moment().subtract(i, 'months').format('MMMM Y'); 
    months.push(month); 
  } 
  return months.reverse(); 
}

// 处理原始价格数据,匹配到12个月的列表中
function processPriceData(priceHistory, targetMonths) {
  // 先创建一个映射表,初始化所有月份的价格为null(无数据时Chart.js会跳过该点)
  const monthPriceMap = {};
  targetMonths.forEach(month => {
    monthPriceMap[month] = null;
  });

  // 遍历你的历史价格数据,转换日期格式并填充价格
  priceHistory.forEach(item => {
    // 解析原始的DD/MM/YYYY格式日期,转换成和目标月份一致的MMMM Y格式
    const itemMonth = moment(item.date, 'DD/MM/YYYY').format('MMMM Y');
    // 如果这个月份在我们的12个月列表里,就填充价格(注意转成数字)
    if (monthPriceMap.hasOwnProperty(itemMonth)) {
      // 如果你有同一个月份的多个价格,可以改成取平均值/最大值,这里我用最后一条数据覆盖
      monthPriceMap[itemMonth] = parseFloat(item.price);
    }
  });

  // 按照目标月份的顺序,提取价格数组
  return targetMonths.map(month => monthPriceMap[month]);
}

第三步:初始化Chart.js图表

现在可以把处理好的数据传入Chart.js,配置坐标轴和样式:

// 获取12个月的标签列表
const months = getPreviousMonths();
// 你的原始价格历史数据
const priceHistory = [ 
  { "price":"49", "date":"21\/01\/2018" }, 
  { "price":"30", "date":"01\/01\/2018" }, 
  { "price":"32", "date":"15\/11\/2017" } 
];
// 处理得到对应每个月份的价格数组
const priceDataset = processPriceData(priceHistory, months);

// 初始化图表
const ctx = document.getElementById('priceChart').getContext('2d');
new Chart(ctx, {
  type: 'line',
  data: {
    labels: months, // X轴直接用我们生成的月份标签
    datasets: [{
      label: '月度价格',
      data: priceDataset,
      borderColor: '#2196F3', // 折线颜色
      backgroundColor: 'rgba(33, 150, 243, 0.1)', // 填充颜色(可选)
      tension: 0.2, // 折线平滑度,0是纯折线
      fill: true, // 是否填充折线下方区域
      spanGaps: false // 无数据时是否跳过断点,设为true会连接前后点
    }]
  },
  options: {
    scales: {
      x: {
        title: {
          display: true,
          text: '月份'
        },
        ticks: {
          maxRotation: 45, // 旋转X轴标签避免重叠
          minRotation: 30
        }
      },
      y: {
        title: {
          display: true,
          text: '价格'
        },
        beginAtZero: true, // Y轴从0开始,如果你不想从0开始可以改成false
        ticks: {
          // 给价格加上货币符号,比如$
          callback: function(value) {
            return `$${value}`;
          }
        }
      }
    },
    plugins: {
      tooltip: {
        // 自定义提示框内容
        callbacks: {
          label: function(context) {
            return `价格: $${context.parsed.y || 'N/A'}`;
          }
        }
      }
    }
  }
});

关键细节说明

  1. 重复月份数据处理:如果你的历史数据中有同一个月份的多条价格(比如例子里2018年1月有两个价格),可以修改processPriceData函数来处理,比如取平均值:
    // 修改初始化部分为数组
    targetMonths.forEach(month => {
      monthPriceMap[month] = [];
    });
    // 填充时push价格
    priceHistory.forEach(item => {
      const itemMonth = moment(item.date, 'DD/MM/YYYY').format('MMMM Y');
      if (monthPriceMap.hasOwnProperty(itemMonth)) {
        monthPriceMap[itemMonth].push(parseFloat(item.price));
      }
    });
    // 最后计算平均值
    return targetMonths.map(month => {
      const prices = monthPriceMap[month];
      if (prices.length === 0) return null;
      return prices.reduce((sum, price) => sum + price, 0) / prices.length;
    });
    
  2. 坐标轴配置:因为我们已经提前处理了月份标签,不需要用Chart.js的时间坐标轴,直接用文本标签更简单。如果需要用时间轴,可以参考Chart.js的时间刻度配置,但这里没必要。
  3. 无数据处理:把无数据的月份设为null,Chart.js会自动跳过这些点,如果你希望折线连接前后点,把spanGaps设为true即可。

内容的提问来源于stack exchange,提问作者Zoker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:41:44