Angular中ApexCharts fill属性报TypeError: Cannot read 'length'问题
Angular中ApexCharts配置fill属性报错"TypeError: Cannot read properties of undefined (reading 'length')"的解决
问题概述
在Angular项目中使用ApexCharts时,配置fill属性的colors函数时抛出错误:TypeError: Cannot read properties of undefined (reading 'length'),但dataLabels使用完全相同的逻辑却能正常工作。打印opts.dataPointIndex仅输出0和1就触发报错,仿佛数组只有2个元素。
代码片段
HTML模板
<apx-chart class="chart" [series]="emodChartConfig.routingOverviewSeries" [chart]="emodChartConfig.routingOverviewChartOptions.chart" [stroke]="emodChartConfig.routingOverviewChartOptions.stroke" [tooltip]="emodChartConfig.routingOverviewChartOptions.tooltip" [fill]="emodChartConfig.routingOverviewChartOptions.fill" [legend]="emodChartConfig.routingOverviewChartOptions.legend" [xaxis]="emodChartConfig.overviewXAxis" [yaxis]="emodChartConfig.routingOverviewChartOptions.yaxis" [plotOptions]="emodChartConfig.routingOverviewChartOptions.plotOptions" [dataLabels]="emodChartConfig.routingOverviewChartOptions.dataLabels" ></apx-chart>
TypeScript代码
async loadOverviewData() { this.monthlyEMODService.getOverviewMonthlyEMOD().subscribe({ next: (data) => { const categories = data.map((item) => IdToUn[item.departmentId]); const routingData = data.map((item) => item.emod); const totalData = data.map((item) => item.pureEMOD); const totalBudget = data.map((item) => item.totalBudget); const routingBudget = data.map((item) => item.routingBudget); this.routingOverviewSeries = [ { name: 'EMOD', type: 'column', data: [...routingData], }, { name: 'Objetivo', type: 'line', data: [...routingBudget], }, ]; this.routingOverviewChartOptions = { dataLabels: { enabled: true, enabledOnSeries: [0], style: { fontSize: '14px', fontWeight: 'bold', colors: [ function (opts: any) { const routingBudget = opts.w.config.series[1].data; const routingData = opts.w.config.series[0].data; return routingData[opts.dataPointIndex] > routingBudget[opts.dataPointIndex] ? '#00FF00' : '#FF0000'; }, ], }, }, plotOptions: { bar: { distributed: true, }, }, fill: { colors: [function(opts:any) { const routingBudget = opts.w.config.series[1].data; const routingData = opts.w.config.series[0].data; return routingData[opts.dataPointIndex] > routingBudget[opts.dataPointIndex] ? '#00FF00' : '#FF0000'; }] }, }; } }); }
接口返回数据示例
[ { "departmentId": 1, "emod": 64.24, "pureEMOD": 59.59, "noCEDISEMOD": null, "noCEDISPureEMOD": null, "totalBudget": 82, "routingBudget": 70 }, { "departmentId": 2, "emod": 84.25, "pureEMOD": 73.05, "noCEDISEMOD": null, "noCEDISPureEMOD": null, "totalBudget": 82, "routingBudget": 86 }, { "departmentId": 3, "emod": 90.32, "pureEMOD": 79.77, "noCEDISEMOD": null, "noCEDISPureEMOD": null, "totalBudget": 85, "routingBudget": 87 }, { "departmentId": 4, "emod": 75.61, "pureEMOD": 67.6, "noCEDISEMOD": null, "noCEDISPureEMOD": null, "totalBudget": 82, "routingBudget": 87 }, { "departmentId": 5, "emod": 89.03, "pureEMOD": 81.18, "noCEDISEMOD": null, "noCEDISPureEMOD": null, "totalBudget": 82, "routingBudget": 85 }, { "departmentId": 6, "emod": 87.12, "pureEMOD": 70.93, "noCEDISEMOD": null, "noCEDISPureEMOD": null, "totalBudget": 82, "routingBudget": 82 }, { "departmentId": 7, "emod": 79.66, "pureEMOD": 70.91, "noCEDISEMOD": 91.23, "noCEDISPureEMOD": 70.91, "totalBudget": 82, "routingBudget": 82 } ]
原因分析
- 系列数量不匹配:你的
series数组包含2个系列(柱状图和折线图),但fill.colors数组只提供了1个颜色函数。当ApexCharts渲染第二个系列时,会尝试读取colors数组的第二个元素,由于该元素不存在,内部逻辑在访问其length属性时抛出错误。 - dataLabels正常的原因:
dataLabels配置了enabledOnSeries: [0],仅对第一个系列生效,不会触发第二个系列的颜色函数逻辑,因此未出现报错。
ApexCharts Fill配置说明(翻译自官方文档)
colors:数组类型,用于设置每个系列的填充颜色。数组索引与系列索引一一对应,每个元素可以是颜色字符串或返回颜色值的函数。- 若某个系列未配置对应颜色,框架会尝试使用默认颜色;但当使用函数作为颜色值时,必须确保每个系列都有对应的函数或值,否则会触发未定义属性访问错误。
解决方案
方案一:补充对应系列的颜色配置
给fill.colors数组添加第二个元素,第二个系列可以设置默认颜色或相同逻辑:
fill: { colors: [ function(opts:any) { const routingBudget = opts.w.config.series[1].data; const routingData = opts.w.config.series[0].data; return routingData[opts.dataPointIndex] > routingBudget[opts.dataPointIndex] ? '#00FF00' : '#FF0000'; }, '#888888' // 给第二个系列设置默认颜色 ] }
方案二:在系列对象中单独配置fill
直接在每个系列的定义中设置fill.color,仅给需要动态颜色的系列配置函数:
this.routingOverviewSeries = [ { name: 'EMOD', type: 'column', data: [...routingData], fill: { color: function(opts:any) { const routingBudget = opts.w.config.series[1].data; const routingData = opts.w.config.series[0].data; return routingData[opts.dataPointIndex] > routingBudget[opts.dataPointIndex] ? '#00FF00' : '#FF0000'; } } }, { name: 'Objetivo', type: 'line', data: [...routingBudget], fill: { color: '#888888' // 折线图的填充颜色 } }, ];
方案三:使用seriesOverride指定特定系列
通过fill.seriesOverride配置仅针对第一个系列应用动态颜色:
fill: { seriesOverride: [ { color: function(opts:any) { const routingBudget = opts.w.config.series[1].data; const routingData = opts.w.config.series[0].data; return routingData[opts.dataPointIndex] > routingBudget[opts.dataPointIndex] ? '#00FF00' : '#FF0000'; } } ], colors: ['#888888'] // 第二个系列使用默认颜色 }
内容的提问来源于stack exchange,提问作者Fernando Hernandez
相关产品推荐
相关产品推荐

