Angular/Ionic项目Firefox下ng2-charts报NS_ERROR_FAILURE错误求助
Angular/Ionic项目中Firefox下ng2-charts+Chart.js的NS_ERROR_FAILURE错误解决思路
问题描述
在Angular/Ionic项目中,仅Firefox浏览器使用ng2-charts和Chart.js时会抛出0x80004005(NS_ERROR_FAILURE)错误,触发点在computeLabelSizes方法,导致应用崩溃,但Chrome和Edge运行正常。
错误栈信息
ERROR Error: Uncaught (in promise): [Exception... "Failure" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: http://localhost:4200/default-src_app_explore-container_explore-container_module_ts.js :: computeLabelSizes :: line 11070" data: no] computeLabelSizes@http://localhost:4200/default-src_app_explore-container_explore-container_module_ts.js:11070:7 _getLabelSizes@http://localhost:4200/default-src_app_explore-container_explore-container_module_ts.js:11730:39 fit@http://localhost:4200/default-src_app_explore-container_explore-container_module_ts.js:11593:29 update@http://localhost:4200/default-src_app_explore-container_explore-container_module_ts.js:11405:10 fitBoxes@http://localhost:4200/default-src_app_explore-container_explore-container_module_ts.js:7044:11 update@http://localhost:4200/default-src_app_explore-container_explore-container_module_ts.js:7254:15 updateLayout@http://localhost:4200/default-src_app_explore-container_explore-container_module_ts.js:9503:20 update@http://localhost:4200/default-src_app_explore-container_explore-container_module_ts.js:9460:10 construct@http://localhost:4200/default-src_app_explore-container_explore-container_module_ts.js:9194:10 Chart@http://localhost:4200/default-src_app_explore-container_explore-container_module_ts.js:9133:10 getChartBuilder@http://localhost:4200/default-src_app_explore-container_explore-container_module_ts.js:35766:12 refresh@http://localhost:4200/default-src_app_explore-container_explore-container_module_ts.js:35975:25 ngOnInit@http://localhost:4200/default-src_app_explore-container_explore-container_module_ts.js:35307:10 callHook@http://localhost:4200/vendor.js:69461:14 callHooks@http://localhost:4200/vendor.js:69417:17 executeInitAndCheckHooks@http://localhost:4200/vendor.js:69353:14 refreshView@http://localhost:4200/vendor.js:80656:35 refreshComponent@http://localhost:4200/vendor.js:81937:18 refreshChildComponents@http://localhost:4200/vendor.js:80369:21 refreshView@http://localhost:4200/vendor.js:80706:29 refreshComponent@http://localhost:4200/vendor.js:81937:18 refreshChildComponents@http://localhost:4200/vendor.js:80369:21 refreshView@http://localhost:4200/vendor.js:80706:29 detectChangesInternal@http://localhost:4200/vendor.js:82097:16 detectChanges@http://localhost:4200/vendor.js:82689:26 setActive@http://localhost:4200/vendor.js:6023:42 activateWith@http://localhost:4200/vendor.js:7170:20 activateRoutes@http://localhost:4200/vendor.js:117943:28 activateChildRoutes/<@http://localhost:4200/vendor.js:117887:12 activateChildRoutes@http://localhost:4200/vendor.js:117886:25 activateRoutes@http://localhost:4200/vendor.js:117950:14 activateChildRoutes/<@http://localhost:4200/vendor.js:117887:12 activateChildRoutes@http://localhost:4200/vendor.js:117886:25 activateRoutes@http://localhost:4200/vendor.js:117946:16 activateChildRoutes/<@http://localhost:4200/vendor.js:117887:12 activateChildRoutes@http://localhost:4200/vendor.js:117886:25 activateRoutes@http://localhost:4200/vendor.js:117950:14 activateChildRoutes/<@http://localhost:4200/vendor.js:117887:12 activateChildRoutes@http://localhost:4200/vendor.js:117886:25 activate@http://localhost:4200/vendor.js:117787:10 activateRoutes/<@http://localhost:4200/vendor.js:117770:99 _next@http://localhost:4200/vendor.js:25460:29 next@http://localhost:4200/vendor.js:23721:12 _next@http://localhost:4200/vendor.js:26324:22 next@http://localhost:4200/vendor.js:23721:12 _next@http://localhost:4200/vendor.js:25466:22 next@http://localhost:4200/vendor.js:23721:12 notifyNext@http://localhost:4200/vendor.js:26033:22 _next@http://localhost:4200/vendor.js:24179:17 next@http://localhost:4200/vendor.js:23721:12 _next@http://localhost:4200/vendor.js:25466:22 next@http://localhost:4200/vendor.js:23721:12 subscribeToArray/<@http://localhost:4200/vendor.js:27123:16 _trySubscribe@http://localhost:4200/vendor.js:23252:19 subscribe@http://localhost:4200/vendor.js:23234:172 call@http://localhost:4200/vendor.js:25443:19 subscribe@http://localhost:4200/vendor.js:23232:25 innerSubscribe@http://localhost:4200/vendor.js:24250:19 _innerSub@http://localhost:4200/vendor.js:26001:93 _next@http://localhost:4200/vendor.js:25988:10 next@http://localhost:4200/vendor.js:23721:12 notifyNext@http://localhost:4200/vendor.js:26033:22 _next@http://localhost:4200/vendor.js:24179:17 next@http://localhost:4200/vendor.js:23721:12 _next@http://localhost:4200/vendor.js:25466:22 next@http://localhost:4200/vendor.js:23721:12 _next@http://localhost:4200/vendor.js:26094:24 next@http://localhost:4200/vendor.js:23721:12 _complete@http://localhost:4200/vendor.js:25164:24 complete@http://localhost:4200/vendor.js:23737:12 _complete@http://localhost:4200/vendor.js:24547:24 complete@http://localhost:4200/vendor.js:23737:12 subscribeToArray/<@http://localhost:4200/vendor.js:27126:14 _trySubscribe@http://localhost:4200/vendor.js:23252:19 subscribe@http://localhost:4200/vendor.js:23234:172 call@http://localhost:4200/vendor.js:24524:19 subscribe@http://localhost:4200/vendor.js:23232:25 call@http://localhost:4200/vendor.js:25145:19 subscribe@http://localhost:4200/vendor.js:23232:25 call@http://localhost:4200/vendor.js:26077:19 subscribe@http://localhost:4200/vendor.js:23232:25 call@http://localhost:4200/vendor.js:25443:19 subscribe@http://localhost:4200/vendor.js:23232:25 innerSubscribe@http://localhost:4200/vendor.js:24250:19 _innerSub@http://localhost:4200/vendor.js:26001:93 _next@http://localhost:4200/vendor.js:25988:10 next@http://localhost:4200/vendor.js:23721:12 notifyNext@http://localhost:4200/vendor.js:26033:22 _next@http://localhost:4200/vendor.js:24179:17 next@http://localhost:4200/vendor.js:23721:12 _next@http://localhost:4200/vendor.js:25466:22 next@http://localhost:4200/vendor.js:23721:12 _next@http://localhost:4200/vendor.js:26324:22 next@http://localhost:4200/vendor.js:23721:12 notifyNext@http://localhost:4200/vendor.js:26033:22 _next@http://localhost:4200/vendor.js:24179:17
报错代码行

复现说明
因ng2-charts起始模板无法正常运行(控制台报404错误),无法提供在线演示,可通过以下步骤复现:创建新的Angular/Ionic项目,安装指定版本依赖,使用如下代码:
项目依赖版本
(注:项目为线上运行状态,无法大幅升级)
{ "@angular/core": "^14.0.0", "@ionic/angular": "^6.1.9", "chart.js": "^2.9.4", "ng2-charts": "^2.4.2" }
触发条件
- 错误仅在Firefox中出现,导致应用崩溃;Chrome和Edge运行正常
- 将scaleLabel和ticks的display设为false后,错误消失
- 即使关闭上述选项,开启
[legend]="true"时错误会再次出现
HTML代码
<div id="container"> <div> <canvas baseChart width="300" height="300" [datasets]="previewChartData" [options]="previewChartOptions" [legend]="false" [chartType]="'line'" ></canvas> </div> </div>
TS代码
public previewChartData = [ { data: [ { title: 'Title', x: 10, y: 20 } ] } ]; public previewChartOptions = { scales: { xAxes: [ { type: 'linear', scaleLabel: { display: true, labelString: 'asd' }, ticks: { display: true } } ], yAxes: [ { type: 'linear', scaleLabel: { display: true, labelString: 'qwe' }, ticks: { display: true } } ] } };
已尝试的解决方法
- 更新ng2-charts和chart.js的小版本
- 将图表移出ngIf指令
- 调整ViewChild的static属性或移除ViewChild
- 删除node_modules后重新安装
- 在项目其他图表上测试相同配置,错误依旧
- 调整图表宽高、父容器样式
- 调整responsive和maintainAspectRatio选项
- 修改报错处的chart.js代码
待尝试的有效解决方法
1. 强制指定图表字体配置
Firefox在Canvas文本渲染上和Chrome有差异,显式设置字体参数避免渲染异常:
public previewChartOptions = { defaultFontFamily: "'Arial', sans-serif", defaultFontSize: 12, defaultFontColor: '#666', scales: { // 原有配置... } };
2. 延迟图表初始化
确保DOM完全渲染后再初始化图表,改用ngAfterViewInit生命周期钩子并添加短暂延迟:
import { Component, AfterViewInit, ViewChild } from '@angular/core'; import { BaseChartDirective } from 'ng2-charts'; export class YourComponent implements AfterViewInit { @ViewChild(BaseChartDirective) chart?: BaseChartDirective; ngAfterViewInit(): void { setTimeout(() => { this.chart?.refresh(); }, 100); } }
3. 修复Chart.js文本测量逻辑
针对Firefox的NS_ERROR_FAILURE错误,修改computeLabelSizes方法的文本测量逻辑,避免触发异常API:
找到Chart.js中该方法,替换文本测量部分:
function computeLabelSizes() { // 保留原有变量定义逻辑 const textMetrics = ctx.measureText(label); return { width: textMetrics.width, height: parseInt(ctx.font.split(' ')[0], 10) || 12 }; }
若无法直接修改node_modules,可使用patch-package工具生成补丁持久化修改。
4. 禁用Firefox硬件加速
通过CSS或JS禁用Canvas硬件加速,避免渲染冲突:
#container canvas { -moz-osx-font-smoothing: grayscale; }
或:
ngAfterViewInit(): void { const canvas = document.querySelector('canvas[baseChart]') as HTMLCanvasElement; const ctx = canvas?.getContext('2d'); if (ctx) { (ctx as any).mozImageSmoothingEnabled = false; } }
5. 调整数据格式
将对象格式的点数据换成数组格式,触发Chart.js不同的渲染分支:
public previewChartData = [ { data: [20], xAxisID: 'x-axis-0' } ]; public previewChartOptions = { scales: { xAxes: [ { type: 'linear', scaleLabel: { display: true, labelString: 'asd' }, ticks: { display: true, min: 0, max: 20, stepSize: 5 } } ], // 原有y轴配置... } };
6. 替换为CDN版本的Chart.js
引入CDN版本的Chart.js(对应2.9.4),替换本地npm包,避免打包兼容性问题:
在index.html中添加:
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.4/dist/Chart.min.js"></script>
同时在angular.json中移除Chart.js的打包配置,确保使用全局Chart对象。
内容的提问来源于stack exchange,提问作者Taha Erden
相关产品推荐
相关产品推荐

