Chart.js v4.4.0在Angular中设置图例左右位置触发运行时错误
Angular中Chart.js v4.4.0饼图图例设为left/right触发options为null的运行时错误解决方法
问题现象
在Angular项目中使用Chart.js v4.4.0创建饼图时,将图例位置从top或bottom修改为left或right,会触发运行时错误。错误出现在Chart.js内部的inRange函数中,提示无法读取null的spacing属性,即this.options为null。
错误代码片段
触发错误的Chart.js内部函数:
inRange(chartX, chartY, useFinalPosition) { const point = this.getProps([ 'x', 'y' ], useFinalPosition); const { angle , distance } = getAngleFromPoint(point, { x: chartX, y: chartY }); const { startAngle , endAngle , innerRadius , outerRadius , circumference } = this.getProps([ 'startAngle', 'endAngle', 'innerRadius', 'outerRadius', 'circumference' ], useFinalPosition); const rAdjust = this.options.spacing / 2; // 此处this.options为null,触发错误 const _circumference = valueOrDefault(circumference, endAngle - startAngle); const betweenAngles = _circumference >= TAU || _angleBetween(angle, startAngle, endAngle); const withinRadius = _isBetween(distance, innerRadius + rAdjust, outerRadius + rAdjust); return betweenAngles && withinRadius; }
问题原因
这是Chart.js v4.4.0的已知bug:当饼图的图例设置为垂直方向(left/right)时,图例项的交互逻辑会错误地访问未初始化的options对象;而水平方向(top/bottom)的图例不会触发该问题。该bug已在后续版本(v4.4.1及以上)中修复。
解决方案
方案1:升级Chart.js版本
直接将Chart.js升级到修复该bug的版本,执行以下命令:
npm install chart.js@4.4.1 --save # 或者升级到最新稳定版 npm install chart.js@latest --save
升级后无需修改原有组件代码,图例设置为left/right即可正常运行。
方案2:临时禁用图例交互
如果不需要图例的点击交互功能,可以在图例配置中添加interactive: false,避免触发错误逻辑:
修改组件中Chart的options配置:
options: { responsive: true, plugins: { legend: { display: true, position: 'right', interactive: false // 禁用图例交互 }, title: { display: true, text: 'Chart.js Pie Chart', }, }, }
方案3:手动补全图例项的options(临时兼容)
如果暂时无法升级版本,可以在Chart初始化完成后,手动为图例项补充默认的options:
修改组件的_initChart函数,在创建chart后添加以下代码:
private _initChart() { const ctx = this._chartPie.nativeElement.getContext('2d'); this.zone.runOutsideAngular(() => { this.chart = new Chart(ctx, { // 原有配置... }); // 手动补全图例项的options if (this.chart?.plugins) { const legendPlugin = this.chart.plugins.find(p => p.id === 'legend'); if (legendPlugin?.legend?.items) { legendPlugin.legend.items.forEach(item => { if (!item.options) { item.options = { spacing: 0 }; } }); } } }); }
原组件代码
@ViewChild('chartPie') private _chartPie: ElementRef<HTMLCanvasElement>; public chart: Chart<'pie'>; public pieChartData = [ { year: 2010, count: 10 }, { year: 2011, count: 20 }, { year: 2012, count: 45 }, ]; constructor(private zone: NgZone) {} ngOnInit(): void { Chart.register(...registerables); } public ngAfterViewInit(): void { this._initChart(); } public ngOnDestroy(): void { if (this.chart) this.chart.destroy(); } private _initChart() { const ctx = this._chartPie.nativeElement.getContext('2d'); this.zone.runOutsideAngular(() => { this.chart = new Chart(ctx, { type: 'pie', data: { labels: this.pieChartData.map((d) => d.year), datasets: [ { label: 'Acquisitions by year', data: this.pieChartData.map((d) => d.count), }, ], }, options: { responsive: true, plugins: { legend: { display: true, position: 'right', // "top/bottom" works fine }, title: { display: true, text: 'Chart.js Pie Chart', }, }, }, }); }); // this.chart.update(); }
内容的提问来源于stack exchange,提问作者Ravi Anand
相关产品推荐
相关产品推荐

