Chart.js 組件註冊

概述

從 Chart.js v3.0 開始,為了支援 tree-shaking 和減少 bundle size,Chart.js 採用了模組化設計。所有的圖表組件(scales、elements、plugins)都需要手動註冊才能使用。本文件說明如何在 Angular 專案中正確註冊 Chart.js 組件。

版本演進對比

ng2-charts v5.x + Chart.js v4.x(舊版本)

// NgChartsModule 內部自動註冊常用組件
import { NgChartsModule } from 'ng2-charts';

@Component({
  imports: [NgChartsModule], // 自動處理註冊
})
export class ChartComponent {}

特點

  • ✅ NgChartsModule 自動註冊常用組件

  • ✅ 開箱即用,無需手動設定

  • 🔶 仍使用 Chart.js v4.x 的模組化架構

  • 🔶 Bundle 包含 NgChartsModule 預設註冊的組件

ng2-charts v6.x+ + Chart.js v4.x(新版本)

// 移除 NgChartsModule,完全交由開發者控制
import { BaseChartDirective } from 'ng2-charts';
import { Chart, CategoryScale, LinearScale, BarElement } from 'chart.js';

// 必須手動註冊組件
Chart.register(CategoryScale, LinearScale, BarElement);

@Component({
  imports: [BaseChartDirective], // 只提供 directive
})
export class ChartComponent {}

特點

  • ✅ 完全控制需要的組件,最佳化 bundle size

  • ✅ 更好的 tree-shaking 支援

  • ✅ 避免不必要的組件載入

  • ❌ 需要手動註冊所有組件

ng2-charts 版本對應

ng2-charts 版本
Chart.js 版本
NgChartsModule
自動註冊
手動註冊
Angular 版本

v4.x

v3.x

✅ 支援

✅ 完全

❌ 不需要

15-16

v5.x

v4.x

✅ 支援

✅ 部分

❌ 不需要

16-17

v6.x

v4.x

❌ 移除

❌ 無

✅ 必須

17+

v8.x

v4.x

❌ 移除

❌ 無

✅ 必須

19+

重要轉折點:ng2-charts v5 → v6

ng2-charts v5.x 的 NgChartsModule 做了什麼?

// NgChartsModule 內部大概是這樣:
@NgModule({
  // 在模組載入時自動註冊常用組件
  imports: [],
  providers: []
})
export class NgChartsModule {
  constructor() {
    // 自動註冊基本組件
    Chart.register(
      CategoryScale,
      LinearScale, 
      BarElement,
      LineElement,
      PointElement,
      Title,
      Tooltip,
      Legend
      // ... 其他常用組件
    );
  }
}

ng2-charts v6.x 的變化

  • 完全移除 NgChartsModule

  • 只提供 BaseChartDirective

  • 所有註冊責任轉移給開發者

註冊方式

方式一:全域註冊(推薦)

main.ts 中註冊所有需要的組件:

// main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { appConfig } from './app/app.config';

// 導入 Chart.js 組件
import { Chart, registerables } from 'chart.js';

// 註冊所有預設組件(最簡單的方式)
Chart.register(...registerables);

bootstrapApplication(AppComponent, appConfig)
  .catch((err) => console.error(err));

方式二:按需註冊(效能最佳)

只註冊專案中實際使用的組件:

// main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { appConfig } from './app/app.config';

// 按需導入組件
import {
  Chart,
  CategoryScale,    // X 軸類別刻度
  LinearScale,      // Y 軸線性刻度
  BarElement,       // 長條圖元素
  LineElement,      // 折線圖元素
  PointElement,     // 點元素
  ArcElement,       // 圓弧元素(餅圖、甜甜圈圖)
  Title,            // 標題插件
  Tooltip,          // 提示框插件
  Legend,           // 圖例插件
  Filler,           // 填充插件
  Colors            // 顏色插件
} from 'chart.js';

// 只註冊需要的組件
Chart.register(
  CategoryScale,
  LinearScale,
  BarElement,
  LineElement,
  PointElement,
  ArcElement,
  Title,
  Tooltip,
  Legend,
  Filler,
  Colors
);

bootstrapApplication(AppComponent, appConfig)
  .catch((err) => console.error(err));

方式三:組件級註冊

在特定組件中註冊(不推薦用於共用組件):

// chart.component.ts
import { Component, OnInit } from '@angular/core';
import { Chart, CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend } from 'chart.js';

@Component({
  selector: 'app-chart',
  // ...
})
export class ChartComponent implements OnInit {
  
  ngOnInit() {
    // 在組件初始化時註冊
    Chart.register(
      CategoryScale,
      LinearScale,
      BarElement,
      Title,
      Tooltip,
      Legend
    );
  }
}

常用組件清單

Scales(刻度)

import {
  CategoryScale,     // 類別刻度(X 軸常用)
  LinearScale,       // 線性刻度(Y 軸常用)
  LogarithmicScale,  // 對數刻度
  RadialLinearScale, // 徑向線性刻度(雷達圖)
  TimeScale,         // 時間刻度
  TimeSeriesScale,   // 時間序列刻度
} from 'chart.js';

Elements(圖表元素)

import {
  BarElement,        // 長條圖
  LineElement,       // 折線圖
  PointElement,      // 點(折線圖的點)
  ArcElement,        // 圓弧(餅圖、甜甜圈圖)
} from 'chart.js';

Plugins(插件)

import {
  Title,             // 標題
  Tooltip,           // 提示框
  Legend,            // 圖例
  Filler,            // 區域填充
  Colors,            // 自動顏色
  Decimation,        // 資料抽樣
  SubTitle,          // 副標題
} from 'chart.js';

Controllers(圖表控制器)

import {
  BarController,     // 長條圖控制器
  LineController,    // 折線圖控制器
  PieController,     // 餅圖控制器
  DoughnutController,// 甜甜圈圖控制器
  RadarController,   // 雷達圖控制器
  ScatterController, // 散佈圖控制器
  BubbleController,  // 泡泡圖控制器
  PolarAreaController,// 極座標區域圖控制器
} from 'chart.js';

圖表類型對應的必要組件

長條圖(Bar Chart)

Chart.register(
  CategoryScale,     // X 軸
  LinearScale,       // Y 軸
  BarElement,        // 長條元素
  Title,             // 標題
  Tooltip,           // 提示框
  Legend             // 圖例
);

折線圖(Line Chart)

Chart.register(
  CategoryScale,     // X 軸
  LinearScale,       // Y 軸
  LineElement,       // 線元素
  PointElement,      // 點元素
  Filler,            // 填充(如果需要區域圖)
  Title,
  Tooltip,
  Legend
);

餅圖(Pie Chart)

Chart.register(
  ArcElement,        // 圓弧元素
  Title,
  Tooltip,
  Legend
);

雷達圖(Radar Chart)

Chart.register(
  RadialLinearScale, // 徑向刻度
  LineElement,       // 線元素
  PointElement,      // 點元素
  Filler,            // 填充
  Title,
  Tooltip,
  Legend
);

常見錯誤排除

錯誤:"category" is not a registered scale

ERROR Error: "category" is not a registered scale.

解決方案:註冊 CategoryScale

import { CategoryScale } from 'chart.js';
Chart.register(CategoryScale);

錯誤:"linear" is not a registered scale

ERROR Error: "linear" is not a registered scale.

解決方案:註冊 LinearScale

import { LinearScale } from 'chart.js';
Chart.register(LinearScale);

錯誤:"bar" is not a registered controller

ERROR Error: "bar" is not a registered controller.

解決方案:註冊 BarController 和 BarElement

import { BarController, BarElement } from 'chart.js';
Chart.register(BarController, BarElement);

最佳實踐

1. 使用 registerables(開發階段)

// 開發階段:快速原型開發
import { Chart, registerables } from 'chart.js';
Chart.register(...registerables);

2. 按需註冊(正式環境)

// 正式環境:最佳化 bundle size
import { Chart, CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend } from 'chart.js';
Chart.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend);

3. 建立註冊模組

// chart-registration.ts
import {
  Chart,
  CategoryScale,
  LinearScale,
  BarElement,
  LineElement,
  PointElement,
  ArcElement,
  Title,
  Tooltip,
  Legend,
  Filler,
  Colors
} from 'chart.js';

export function registerChartComponents() {
  Chart.register(
    CategoryScale,
    LinearScale,
    BarElement,
    LineElement,
    PointElement,
    ArcElement,
    Title,
    Tooltip,
    Legend,
    Filler,
    Colors
  );
}

// main.ts
import { registerChartComponents } from './chart-registration';
registerChartComponents();

Bundle Size 比較

全部註冊 vs 按需註冊

註冊方式
Bundle Size
載入時間
適用場景

全部註冊 (registerables)

~180KB

較慢

開發階段、多種圖表

按需註冊(基本組件)

~60KB

較快

正式環境、特定圖表

按需註冊(最小組件)

~40KB

最快

正式環境、單一圖表

升級指引

從 ng2-charts v5.x 升級到 v6.x

1. 更新依賴:

# 檢查目前版本
npm list ng2-charts chart.js

# 更新到新版本
npm install ng2-charts@^6.0.1 chart.js@^4.5.0

2. 修改 import(關鍵變更):

// ❌ 舊版本(v5.x)
import { NgChartsModule } from 'ng2-charts';

@Component({
  imports: [NgChartsModule] // NgChartsModule 已被移除
})

// ✅ 新版本(v6.x)
import { BaseChartDirective } from 'ng2-charts';

@Component({
  imports: [BaseChartDirective] // 改用 BaseChartDirective
})

3. 新增組件註冊(必要步驟):

// main.ts 中加入
import { Chart, registerables } from 'chart.js';

// 註冊所有組件(推薦用於升級過渡期)
Chart.register(...registerables);

bootstrapApplication(AppComponent, appConfig)
  .catch((err) => console.error(err));

4. 驗證升級結果:

# 啟動開發伺服器
ng serve

# 檢查是否出現以下錯誤:
# "category" is not a registered scale
# "linear" is not a registered scale  
# "bar" is not a registered controller

升級檢查清單

  • [ ] 更新 package.json 依賴版本

  • [ ] 將所有 NgChartsModule 改為 BaseChartDirective

  • [ ] 在 main.ts 中加入 Chart.register(...registerables)

  • [ ] 移除 imports 中的 NgChartsModule

  • [ ] 測試所有圖表功能正常

  • [ ] 檢查 bundle size 是否如預期

常見升級問題

問題 1:Import 錯誤

// 錯誤訊息
Module '"ng2-charts"' has no exported member 'NgChartsModule'

// 解決方案
// 將所有 NgChartsModule 改為 BaseChartDirective

問題 2:Scale 註冊錯誤

// 錯誤訊息
"category" is not a registered scale

// 解決方案
// 在 main.ts 加入組件註冊
import { Chart, registerables } from 'chart.js';
Chart.register(...registerables);

結論

ng2-charts v5 → v6 的升級帶來了重要的架構變更:

為什麼需要手動註冊?

ng2-charts v5.x 時代

  • NgChartsModule 在載入時自動註冊常用的 Chart.js 組件

  • 開發者無感,開箱即用

  • 但無法精確控制載入的組件

ng2-charts v6.x 變更

  • 移除 NgChartsModule,將控制權完全交給開發者

  • 需要手動註冊所有需要的 Chart.js 組件

  • 更好的 tree-shaking 和 bundle size 控制

效能影響分析

版本組合
Bundle Size
載入方式
適用場景

v5 + NgChartsModule

~120KB

自動載入預設組件

快速開發

v6 + 全部註冊

~180KB

手動載入所有組件

多種圖表

v6 + 按需註冊

~40-60KB

手動載入需要組件

正式環境

升級建議

  1. 升級過渡期:使用 Chart.register(...registerables) 確保功能正常

  2. 優化階段:分析實際使用的圖表類型,改用按需註冊

  3. 維護階段:建立團隊的組件註冊標準和最佳實踐

這個變更雖然增加了設定複雜度,但提供了更好的效能控制能力,特別適合對 bundle size 敏感的正式環境。

Last updated