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

在xx.ts控制器中实现HighCharts时出现Cannot read properties of undefined错误

HighCharts开启shared:true后报错"Cannot read properties of undefined (reading 'color')"的解决方法

问题说明

首次在项目中实现HighCharts,多系列图表原本运行正常,为实现单个tooltip显示多个系列值,添加shared:true配置后出现错误:Cannot read properties of undefined (reading 'color'),尝试split:true配置也无效。

错误信息

TChartController.ts:942 Uncaught TypeError: Cannot read properties of undefined (reading 'color')
at Object.formatter (TChartController.ts:942:81)
at f.refresh (highstock.js:238:71)
at highcharts-theme.js:60:25 formatter @ TChartController.ts:942 f.refresh @ highstock.js:238 (anonymous) @ highcharts-theme.js:60
setTimeout (async) (anonymous) @ highcharts-theme.js:57 b. @
highstock.js:21 t.runPointActions @ highstock.js:270
t.onContainerMouseMove @ highcharts.js:262

相关代码

tooltip: {
    getLabelOverride: this.allowAngularContentInTooltip,
    shared: true,
    useHTML: true,
    
    formatter: function ()
    {
        const highchartsFormatterContext = this;
        const numItems = highchartsFormatterContext.y;
        const viewItemsFiltersForDataPoint = highchartsFormatterContext.point?.additionalData?.viewItemsFilters;
        
        self.setViewItemsFilters(numItems, viewItemsFiltersForDataPoint);
    
        if (self.viewItemsFilters?.seriesId && self.multipleSeriesFilters?.length)
        {
            const seriesFilters = self.multipleSeriesFilters.find(x => x.seriesId === self.viewItemsFilters.seriesId || x.SeriesId === self.viewItemsFilters.seriesId);

            if (seriesFilters)
            {
                const mergedFilters = { ...seriesFilters, ...self.viewItemsFilters };

                self.viewItemsFilters = mergedFilters;
            }
        }

        let tooltipHeader: string;

        if (highchartsFormatterContext.point?.additionalData?.tooltip)
        {
            tooltipHeader = highchartsFormatterContext.point?.additionalData?.tooltip;
        }
        else
        {
            const dateFormat = self.intervalUnit
                ? self.intervalTooltipDateFormats[self.intervalUnit]
                : 'month';

            tooltipHeader = Highcharts.dateFormat(dateFormat, highchartsFormatterContext.key);
        }

        let valueString = Highcharts.numberFormat(highchartsFormatterContext.y, 0);

        if (highchartsFormatterContext.series?.tooltipOptions?.valuePrefix)
        {
            valueString = `${highchartsFormatterContext.series.tooltipOptions.valuePrefix}${valueString}`;
        }
        if (highchartsFormatterContext.series?.tooltipOptions?.valueSuffix)
        {
            valueString = `${valueString}${highchartsFormatterContext.series.tooltipOptions.valueSuffix}`;
        }

        const headerHtml = `<span style="font-size:10px;">${tooltipHeader}</span><br />`;                   
        const pointHtml = `<span style="color:${highchartsFormatterContext.series.color}">●</span> ${highchartsFormatterContext.series.name}: <b>${valueString}</b><br/>`;

        const footerHtml = self.generateViewItemsButtonMarkup();
                        
        return `${headerHtml}${pointHtml}${footerHtml}`;
    },
    stickOnContact: true,
    style: {
        pointerEvents: 'auto'
    }
    
},
    
plotOptions: {
    series: {
        connectNulls: true,
        events: {
            click: (event) =>
            {
                const dataPointLinkedWidgetFilters = event.point?.additionalData?.linkedWidgetFilters;

                if (!dataPointLinkedWidgetFilters)
                {
                    return;
                }

                const filterType: FilterType = this.getFilterType();

                if (!filterType)
                {
                    return;
                }

                this.sendLinkedWidgetFiltersData(
                    dataPointLinkedWidgetFilters,
                    filterType);
            }
        }
    
}

原因分析

开启shared: true后,HighCharts的tooltip formatter上下文结构发生变化:

  • 非shared模式下,this指向单个数据点,可直接访问series、y、point等属性
  • shared模式下,this指向包含所有系列数据点的集合对象,原有的单个点属性会变为undefined,需要通过this.points数组获取每个系列的点数据。代码中直接访问highchartsFormatterContext.series.color自然会报错。

修复方案

修改formatter函数,适配shared模式的上下文结构:

formatter: function () {
    const self = this;
    let tooltipHeader;

    // 获取tooltip头部标题
    const firstPoint = self.points[0];
    if (firstPoint.point?.additionalData?.tooltip) {
        tooltipHeader = firstPoint.point.additionalData.tooltip;
    } else {
        const dateFormat = self.intervalUnit
            ? self.intervalTooltipDateFormats[self.intervalUnit]
            : 'month';
        tooltipHeader = Highcharts.dateFormat(dateFormat, self.key);
    }

    let headerHtml = `<span style="font-size:10px;">${tooltipHeader}</span><br />`;
    let pointsHtml = '';

    // 遍历所有系列的点,生成每个系列的tooltip内容
    self.points.forEach(point => {
        let valueString = Highcharts.numberFormat(point.y, 0);
        
        // 处理数值前缀后缀
        if (point.series?.tooltipOptions?.valuePrefix) {
            valueString = `${point.series.tooltipOptions.valuePrefix}${valueString}`;
        }
        if (point.series?.tooltipOptions?.valueSuffix) {
            valueString = `${valueString}${point.series.tooltipOptions.valueSuffix}`;
        }

        // 处理视图筛选器逻辑
        const viewItemsFiltersForDataPoint = point.point?.additionalData?.viewItemsFilters;
        if (viewItemsFiltersForDataPoint) {
            self.setViewItemsFilters(point.y, viewItemsFiltersForDataPoint);
            
            if (self.viewItemsFilters?.seriesId && self.multipleSeriesFilters?.length) {
                const seriesFilters = self.multipleSeriesFilters.find(x => 
                    x.seriesId === self.viewItemsFilters.seriesId || x.SeriesId === self.viewItemsFilters.seriesId);
                
                if (seriesFilters) {
                    self.viewItemsFilters = { ...seriesFilters, ...self.viewItemsFilters };
                }
            }
        }

        // 拼接单个系列的HTML内容
        pointsHtml += `<span style="color:${point.series.color}">●</span> ${point.series.name}: <b>${valueString}</b><br/>`;
    });

    const footerHtml = self.generateViewItemsButtonMarkup();
    return `${headerHtml}${pointsHtml}${footerHtml}`;
}

注意事项

  • shared模式下必须通过this.points数组访问各系列的点数据,原单个点的series、y等属性不再可用
  • 头部标题可根据需求取第一个点的附加tooltip内容,或使用上下文的key统一格式化
  • 如果需要处理每个点的附加数据,需遍历points数组逐个处理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 16:44:55