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

使用Chart.js绘制无年份时间轴:解决季节累计数据排序问题

问题描述

我想用Chart.js绘制每日累计总和折线图,每个季节(10月至次年9月)对应一条折线。数据存在PostgreSQL表中,结构如下:

date        season  cum_sum
2021-12-23  2022    11
2022-01-01  2022    19
2022-01-04  2022    20
2022-01-05  2022    40 
2022-03-01  2022    43
2022-12-01  2023    3
2022-12-02  2023    7
2022-12-10  2023    11
2022-12-23  2023    17
2023-01-01  2023    19
2023-01-05  2023    30

当前遇到两个问题:

  • x轴未按季节时间顺序排列:2023季中2022季没有的日期会被挤到x轴末尾
  • 10-12月作为季初,却被显示在x轴末尾,顺序完全颠倒

当前使用的JS代码如下:

$( document ).ready(function() {
    // retrieve data from PHP as JSON object using fetch API
    fetch('./inc/get_data.php')
    .then(response => response.json())
    .then(baseData  => {
        const data_2022 = baseData['2022'].map(arr => ({ x: arr[0], y: parseFloat(arr[1])}));
        const data_2023 = baseData['2023'].map(arr => ({ x: arr[0], y: parseFloat(arr[1])}));
        // create chart
        var ctx = document.getElementById('myChart').getContext('2d');
        var chart = new Chart(ctx, {
        type: 'line',
        data: {
            datasets: [{
                label: 'Season 2022',
                data: data_2022,
                borderColor: 'blue',
                fill: false 
                }, {
                label: 'Season 2023',
                data: data_2023,
                borderColor: 'red',
                fill: false
            }]
        },
        options: {
            scales: {
                xAxes: [{
                    type: 'time',
                    time: {
                        unit: 'day',
                        unitStepSize: 1,
                        displayFormats: {
                            'day': 'MMM DD'
                        },
                        tooltipFormat: 'MM-DD',
                    }
                }],
            yAxes: [{
                ticks: {
                    beginAtZero: true
                }
            }]
            }
        }
        });
    })
    .catch(error => console.error(error));
});
解决方案

核心解决思路是把每个季节的日期转换为「季节基准虚拟日期」,让Chart.js把10月-次年9月当成一个连续的时间区间,而非按公历年份排序。具体步骤如下:

1. 前端预处理:转换日期为季节对齐格式

给每条数据的日期做年份替换:

  • 如果原日期是10-12月,年份直接用所属季节的年份
  • 如果原日期是1-9月,年份用「季节年份-1」

举个例子:

  • 2021-12-23(属于2022季节)→ 转成 2022-12-23
  • 2022-01-01(属于2022季节)→ 转成 2021-01-01

这样处理后,每个季节的日期都会形成「YYYY-10-01」到「YYYY+1-09-30」的连续区间,10-12月自然会排在1-9月前面。

修改JS中的数据处理逻辑:

// 日期转换工具函数
function convertToSeasonDate(dateStr, season) {
    const date = new Date(dateStr);
    const month = date.getMonth() + 1; // JS月份从0开始,转成1-12格式
    let year = season;
    // 1-9月属于季节年份的前一年
    if (month <= 9) {
        year -= 1;
    }
    // 构造新日期字符串,保持月日不变,替换年份
    return `${year}-${String(month).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
}

// 处理数据时应用转换
const data_2022 = baseData['2022'].map(arr => ({ 
    x: convertToSeasonDate(arr[0], 2022), 
    y: parseFloat(arr[1])
}));
const data_2023 = baseData['2023'].map(arr => ({ 
    x: convertToSeasonDate(arr[0], 2023), 
    y: parseFloat(arr[1])
}));

2. 调整Chart.js的x轴配置

确保x轴按时间升序排列,并且只显示月日(隐藏虚拟年份):

options: {
    scales: {
        // 注意:如果用Chart.js v2版本,保持xAxes数组写法;v3+用x对象
        x: {
            type: 'time',
            time: {
                unit: 'day',
                displayFormats: {
                    day: 'MMM DD'
                },
                tooltipFormat: 'MM-DD'
            },
            parser: 'yyyy-MM-dd', // 明确日期解析格式,避免识别错误
            reverse: false, // 强制升序排列
            title: {
                display: true,
                text: '日期(季节:10月-次年9月)'
            }
        },
        y: {
            ticks: {
                beginAtZero: true
            },
            title: {
                display: true,
                text: '累计总和'
            }
        }
    }
}

3. 可选:后端提前处理日期(更高效)

如果能修改PHP接口get_data.php,建议直接在PostgreSQL查询时完成日期转换,减少前端工作量:

SELECT 
    CASE 
        WHEN EXTRACT(MONTH FROM date) >= 10 THEN 
            TO_CHAR(date, '"' || season || '"-"MM"-"DD"')::DATE
        ELSE 
            TO_CHAR(date, '"' || (season - 1) || '"-"MM"-"DD"')::DATE
    END AS season_date,
    cum_sum,
    season
FROM your_table
ORDER BY season, season_date;

前端直接用返回的season_date即可,无需再做转换。

最终效果

处理后x轴会严格按季节时间顺序排列:10月→11月→12月→1月→2月→…→9月,不同季节的相同月日会自动对齐,缺失日期也不会乱跑到轴的末尾。


内容的提问来源于stack exchange,提问作者erik-stengel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 09:07:56