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

基于Highcharts的17个月图表年份计算问题(TypeScript)

Highcharts柱状图Tooltip年份计算错误修复

问题背景

现有一个涵盖17个月的Highcharts柱状图,包含回溯12个月与前瞻6个月的数据。当前为5月,回溯12个月的起点为5月,前瞻6个月的终点为11月。需要在tooltip中为每个月份显示对应年份,且并列的两列中,左侧列需显示对应年份的前一年(如左柱显示2022、右柱显示2023),但当前年份计算逻辑始终有误。

现有代码

private getSeriesDataFromGraphData(graphData: GetPreviousYearGraphData[]): Highcharts.PointOptionsObject[] {
    return graphData.map(({y, b2b, b2c, normal}) => ({y, b2b, b2c, normal}));
}

// Using the search-filters does not affect this graph. This graph is only affected when filtering between brands.
private renderOrderAmountCompareOnBrand(
    strCurrencyCode: string,
    arrCategories: string[],
    arrPrevSeriesDataStock: GetPreviousYearGraphData[],
    arrPrevSeriesDataPre: GetPreviousYearGraphData[],
    arrSeriesDataStock: GetPreviousYearGraphData[],
    arrSeriesDataPre: GetPreviousYearGraphData[]
) {
    // Get the series data for each set of graph data
    const prevSeriesDataStock = this.getSeriesDataFromGraphData(arrPrevSeriesDataStock);
    const prevSeriesDataPre = this.getSeriesDataFromGraphData(arrPrevSeriesDataPre);
    const seriesDataStock = this.getSeriesDataFromGraphData(arrSeriesDataStock);
    const seriesDataPre = this.getSeriesDataFromGraphData(arrSeriesDataPre);

    this.OrderAmountComparedOnBrandChart = Highcharts.chart('claimsOrderAmountPerSalesChannel', {
            chart: {
                type: 'column'
            },
            title: {
                text: 'Order amount compared on brand'
            },
            xAxis: {
                categories: arrCategories
            },
            yAxis: {
                allowDecimals: false,
                min: 0,
                title: {
                    text: 'Brand order statistics'
                }
            },
            tooltip: {
                formatter: function () {
                    let strStyling = "display: flex; justify-content: space-between; gap: 20px;";
                    let startDate: Date = new Date();

                    startDate.setMonth(startDate.getMonth() - 12);

                    let year = startDate.getFullYear();

                    if (!this.series.name.includes('Previous year')) {
                        year += 1;
                    }

                    const GetPreviousYearGraphData = this.point as GetPreviousYearGraphData;

                    return `
                        <b>${this.point.category} | ${this.series.name} | ${year}</b><br><br>
                        <div style="${strStyling}">
                            <span><b>Sales staff:</b></span> ${Highcharts.numberFormat(GetPreviousYearGraphData.normal || 0, 0)} ${strCurrencyCode ?? ''}<br>
                        </div>
                        <div style="${strStyling}">
                            <span><b>B2B:</b></span> ${Highcharts.numberFormat(GetPreviousYearGraphData.b2b || 0, 0)} ${strCurrencyCode ?? ''}<br>
                        </div>
                        <div style="${strStyling}">
                            <span><b>B2C:</b></span> ${Highcharts.numberFormat(GetPreviousYearGraphData.b2c || 0, 0)} ${strCurrencyCode ?? ''}<br>
                        </div>
                        <div style="${strStyling}">
                            <span><b>Total:</b></span> ${Highcharts.numberFormat(this.y || 0, 0)} ${strCurrencyCode ?? ''}
                        </div>
                    `;
                },
                useHTML: true
            },
            plotOptions: {
                column: {
                    stacking: 'normal',
                    dataLabels: {
                        enabled: false
                    }
                }
            },
            series: [
                {
                    name: 'Stock Previous year',
                    data: prevSeriesDataStock,
                    stack: 'Stock1'
                },
                {
                    name: 'Pre Previous year',
                    data: prevSeriesDataPre,
                    stack: 'Stock1'
                },
                {
                    name: 'Stock',
                    data: seriesDataStock,
                    stack: 'Stock'
                },
                {
                    name: 'Pre',
                    data: seriesDataPre,
                    stack: 'Stock'
                }
            ] as SeriesOptionsType[]
        } as Options
    );
}

问题分析

当前代码仅基于当前日期减12个月的固定逻辑计算年份,再通过系列名称判断是否加1,完全没有结合数据点对应的具体月份位置(回溯/前瞻期),无法适配跨年度的月份区间(比如回溯12个月包含去年5月到今年4月,前瞻6个月是今年5月到11月),导致年份显示与实际月份不匹配。

解决方案

结合当前月份、数据点索引、系列类型三个维度精准计算年份,修改后的tooltip formatter代码如下:

tooltip: {
    formatter: function () {
        let strStyling = "display: flex; justify-content: space-between; gap: 20px;";
        const currentDate = new Date();
        const currentYear = currentDate.getFullYear();
        const currentMonth = currentDate.getMonth(); // 0代表1月,4代表5月
        const pointIndex = this.point.index;
        const isPreviousYearSeries = this.series.name.includes('Previous year');
        
        let targetYear: number;
        
        // 前12个数据点:回溯12个月(去年5月到今年4月)
        if (pointIndex < 12) {
            const targetMonthOffset = currentMonth + pointIndex;
            // 若偏移后月份超过12,说明是今年的月份,否则是去年的
            targetYear = currentYear - (targetMonthOffset >= 12 ? 0 : 1);
        } else {
            // 后6个数据点:前瞻6个月(今年5月到11月)
            targetYear = currentYear;
        }
        
        // 前一年系列统一减1,实现左柱显示前一年的需求
        if (isPreviousYearSeries) {
            targetYear -= 1;
        }

        const pointData = this.point as GetPreviousYearGraphData;

        return `
            <b>${this.point.category} | ${this.series.name} | ${targetYear}</b><br><br>
            <div style="${strStyling}">
                <span><b>Sales staff:</b></span> ${Highcharts.numberFormat(pointData.normal || 0, 0)} ${strCurrencyCode ?? ''}<br>
            </div>
            <div style="${strStyling}">
                <span><b>B2B:</b></span> ${Highcharts.numberFormat(pointData.b2b || 0, 0)} ${strCurrencyCode ?? ''}<br>
            </div>
            <div style="${strStyling}">
                <span><b>B2C:</b></span> ${Highcharts.numberFormat(pointData.b2c || 0, 0)} ${strCurrencyCode ?? ''}<br>
            </div>
            <div style="${strStyling}">
                <span><b>Total:</b></span> ${Highcharts.numberFormat(this.y || 0, 0)} ${strCurrencyCode ?? ''}
            </div>
        `;
    },
    useHTML: true
},

逻辑说明

  • 回溯期(前12个点):通过月份偏移量判断是否跨年度,动态计算基础年份
  • 前瞻期(后6个点):直接使用当前年份
  • 所有含“Previous year”的系列年份减1,满足左柱显示前一年的要求
  • 适配任意当前月份,无需硬编码年份值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 16:07:03