Chart.js 教程
Chart.js 教程
Chart.js 是一款轻量、开源的 JavaScript 图表库,基于 HTML5 Canvas 绘制,支持 8 种核心图表类型,API 简洁,是数据可视化的入门首选。
核心特性
- 轻量:压缩后仅约 60KB,无外部依赖
- 响应式:自动适配容器大小与移动端
- 动画:内置平滑动画与过渡效果
- 8 种图表:折线、柱状、饼图、环形、雷达、极地、散点、气泡、混合
- 可扩展:插件系统(缩放、标签、自定义)
引入方式
<!-- CDN --> <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script> # npm npm install chart.js
第一个图表
<canvas id="myChart"></canvas>
<script>
const ctx = document.getElementById("myChart");
new Chart(ctx, {
type: "bar", // 图表类型
data: {
labels: ["周一", "周二", "周三"],
datasets: [{
label: "访问量",
data: [120, 150, 180],
backgroundColor: "#3498db"
}]
},
options: {
responsive: true,
scales: {
y: { beginAtZero: true }
}
}
});
</script>
学习路线
- 安装与基本使用
- 各图表类型(柱形/气泡/环形/饼图/折线/混合/极地/雷达/散点)
- 配置与自定义
Chart.js 安装
Chart.js 安装
1. CDN 引入
<!-- 最新版本 --> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <!-- 指定版本 --> <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script> <!-- 中国镜像(可选) --> <script src="https://cdn.bootcdn.net/ajax/libs/Chart.js/4.4.0/chart.umd.min.js"></script>
2. npm 安装
# 安装
npm install chart.js
# 导入(ES Module)
import Chart from "chart.js/auto";
# 或按需导入
import { Chart, BarController, BarElement,
CategoryScale, LinearScale } from "chart.js";
Chart.register(BarController, BarElement,
CategoryScale, LinearScale);
3. 浏览器模块
// 直接使用全局对象
const ctx = document.getElementById("chart");
new Chart(ctx, { type: "bar", data: {...} });
// Vue 集成
npm install vue-chartjs chart.js
// React 集成
npm install react-chartjs-2 chart.js
4. 验证安装
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0"></script>
</head>
<body>
<canvas id="demo" width="400" height="200"></canvas>
<script>
new Chart(document.getElementById("demo"), {
type: "line",
data: {
labels: ["A", "B", "C"],
datasets: [{ data: [1, 2, 3] }]
}
});
</script>
</body>
</html>
5. 版本说明
Chart.js 2.x 旧版(option 结构不同) Chart.js 3.x 重构,scale 配置变化 Chart.js 4.x 当前稳定版 # 3/4 版本注意: scales.y.ticks 等配置层级变化
Chart.js 使用
Chart.js 使用
1. 核心结构
new Chart(ctx, {
type: "bar", // 图表类型
data: { // 数据
labels: [...], // 标签(X 轴)
datasets: [{ // 数据集数组
label: "...", // 系列名
data: [...], // 数据值
backgroundColor: "...",
borderColor: "..."
}]
},
options: { // 配置
responsive: true,
plugins: {...},
scales: {...}
}
});
2. 数据配置
data: {
labels: ["北京", "上海", "广州"],
datasets: [
{
label: "2025年",
data: [100, 120, 90],
backgroundColor: "rgba(52,152,219,0.5)",
borderColor: "#2980b9",
borderWidth: 2
},
{
label: "2026年",
data: [130, 140, 110],
backgroundColor: "rgba(46,204,113,0.5)",
borderColor: "#27ae60",
borderWidth: 2
}
]
}
3. 常用配置
options: {
responsive: true, // 响应式
maintainAspectRatio: false, // 不保持比例
animation: {
duration: 1000, // 动画时长
easing: "easeOutBounce"
},
plugins: {
title: {
display: true,
text: "图表标题",
font: { size: 18 }
},
legend: {
display: true,
position: "top"
},
tooltip: {
enabled: true,
callbacks: {
label: (ctx) => ctx.dataset.label + ": " + ctx.parsed.y
}
}
},
scales: {
x: { title: { display: true, text: "X 轴" } },
y: {
title: { display: true, text: "Y 轴" },
beginAtZero: true
}
}
}
4. 更新与销毁
const chart = new Chart(ctx, {...});
// 更新数据
chart.data.datasets[0].data = [10, 20, 30];
chart.update();
// 添加数据
chart.data.labels.push("D");
chart.data.datasets[0].data.push(40);
chart.update();
// 删除数据
chart.data.labels.pop();
chart.data.datasets[0].data.pop();
chart.update();
// 销毁
chart.destroy();
5. 事件处理
options: {
onClick: (event, elements, chart) => {
if (elements.length > 0) {
const index = elements[0].index;
console.log("点击了:", chart.data.labels[index]);
}
},
onHover: (event, elements) => {
// 悬停时 canvas 光标
event.native.target.style.cursor =
elements.length > 0 ? "pointer" : "default";
}
}
Chart.js 柱形图
Chart.js 柱形图
1. 基本柱形图
<canvas id="barChart"></canvas>
<script>
new Chart(document.getElementById("barChart"), {
type: "bar",
data: {
labels: ["一月", "二月", "三月", "四月", "五月"],
datasets: [{
label: "销售额",
data: [120, 150, 130, 180, 200],
backgroundColor: "rgba(52,152,219,0.7)",
borderColor: "#2980b9",
borderWidth: 2
}]
},
options: {
responsive: true,
scales: {
y: { beginAtZero: true }
}
}
});
</script>
2. 多系列柱形
datasets: [
{
label: "线上",
data: [60, 80, 70, 90, 100],
backgroundColor: "#3498db"
},
{
label: "线下",
data: [60, 70, 60, 90, 100],
backgroundColor: "#2ecc71"
}
]
3. 堆叠柱形
options: {
scales: {
x: { stacked: true },
y: { stacked: true, beginAtZero: true }
}
},
datasets: [
{ label: "A产品", data: [30, 40, 50], backgroundColor: "#3498db" },
{ label: "B产品", data: [20, 30, 40], backgroundColor: "#2ecc71" },
{ label: "C产品", data: [15, 20, 25], backgroundColor: "#f39c12" }
]
4. 横向柱形图
// indexAxis: "y" 横向
new Chart(ctx, {
type: "bar",
data: {...},
options: {
indexAxis: "y", // 横向
scales: {
x: { beginAtZero: true }
}
}
});
5. 圆角与渐变
datasets: [{
data: [30, 50, 40],
borderRadius: 8, // 圆角
backgroundColor: (context) => {
// 渐变填充
const { ctx, chartArea } = context.chart;
if (!chartArea) return "#3498db";
const gradient = ctx.createLinearGradient(
0, chartArea.bottom, 0, chartArea.top);
gradient.addColorStop(0, "rgba(52,152,219,0.2)");
gradient.addColorStop(1, "rgba(52,152,219,1)");
return gradient;
}
}]
Chart.js 气泡图
Chart.js 气泡图
1. 基本气泡图
<canvas id="bubbleChart"></canvas>
<script>
new Chart(document.getElementById("bubbleChart"), {
type: "bubble",
data: {
datasets: [{
label: "产品",
data: [
{ x: 10, y: 20, r: 15 }, // r: 气泡半径
{ x: 20, y: 35, r: 25 },
{ x: 30, y: 25, r: 20 },
{ x: 40, y: 50, r: 30 }
],
backgroundColor: "rgba(52,152,219,0.6)"
}]
},
options: {
scales: {
x: { title: { display: true, text: "销量" } },
y: { title: { display: true, text: "利润" } }
}
}
});
</script>
2. 多系列气泡
datasets: [
{
label: "A组",
data: [{x:10,y:20,r:15},{x:20,y:30,r:20}],
backgroundColor: "rgba(52,152,219,0.6)"
},
{
label: "B组",
data: [{x:15,y:40,r:18},{x:30,y:20,r:25}],
backgroundColor: "rgba(231,76,60,0.6)"
}
]
3. 气泡大小调整
// r 值对应像素半径
// 可用函数控制
data: [
{ x: 10, y: 20, r: Math.sqrt(100) * 2 },
{ x: 20, y: 35, r: Math.sqrt(400) * 2 }
]
4. 边界与动画
options: {
animation: {
duration: 800,
easing: "easeInOutQuad"
},
scales: {
x: { min: 0, max: 50 },
y: { min: 0, max: 60 }
},
plugins: {
tooltip: {
callbacks: {
label: (ctx) => {
const d = ctx.raw;
return ctx.dataset.label +
": 销量" + d.x +
" 利润" + d.y +
" 规模" + d.r;
}
}
}
}
}
Chart.js 环形图
Chart.js 环形图
1. 基本环形图
<canvas id="doughnutChart"></canvas>
<script>
new Chart(document.getElementById("doughnutChart"), {
type: "doughnut",
data: {
labels: ["直接访问", "搜索引擎", "社交媒体", "邮件"],
datasets: [{
data: [40, 30, 20, 10],
backgroundColor: [
"#3498db", "#2ecc71", "#f39c12", "#e74c3c"
],
borderWidth: 2,
borderColor: "#fff"
}]
},
options: {
plugins: {
legend: {
position: "bottom"
}
}
}
});
</script>
2. 环形宽度控制
options: {
cutout: "60%" // 内部挖空比例(0=饼图, 60%=环形)
}
// 环形图: cutout 设置内部半径百分比
// 饼图: cutout: 0 或使用 type: "pie"
3. 环形图文字中心
// 使用插件在中心显示文字
const centerText = {
id: "centerText",
afterDraw(chart) {
const { ctx } = chart;
const meta = chart.getDatasetMeta(0);
const x = meta.data[0].x;
const y = meta.data[0].y;
ctx.save();
ctx.textAlign = "center";
ctx.fillStyle = "#333";
ctx.font = "bold 24px sans-serif";
ctx.fillText("总计", x, y - 10);
ctx.font = "16px sans-serif";
ctx.fillText("100%", x, y + 20);
ctx.restore();
}
};
new Chart(ctx, {
type: "doughnut",
data: {...},
options: {...},
plugins: [centerText]
});
4. 交互与动画
options: {
cutout: "55%",
animation: {
animateRotate: true, // 旋转动画
animateScale: true // 缩放动画
},
plugins: {
legend: {
position: "right",
labels: { padding: 20, usePointStyle: true }
},
tooltip: {
callbacks: {
label: (ctx) => {
const total = ctx.dataset.data.reduce(
(a, b) => a + b, 0);
const pct = Math.round(
ctx.parsed / total * 100);
return ctx.label + ": " + ctx.parsed +
" (" + pct + "%)";
}
}
}
}
}
Chart.js 饼图
Chart.js 饼图
1. 基本饼图
<canvas id="pieChart"></canvas>
<script>
new Chart(document.getElementById("pieChart"), {
type: "pie",
data: {
labels: ["Chrome", "Edge", "Firefox", "Safari", "其他"],
datasets: [{
data: [65, 12, 8, 10, 5],
backgroundColor: [
"#3498db", "#2ecc71", "#f39c12",
"#9b59b6", "#95a5a6"
],
borderWidth: 2,
borderColor: "#fff"
}]
},
options: {
plugins: {
legend: {
position: "bottom",
labels: { usePointStyle: true }
},
title: {
display: true,
text: "浏览器市场份额",
font: { size: 16 }
}
}
}
});
</script>
2. 显示百分比
options: {
plugins: {
tooltip: {
callbacks: {
label: (ctx) => {
const total = ctx.dataset.data.reduce(
(a, b) => a + b, 0);
const pct = ((ctx.parsed / total) * 100).toFixed(1);
return ctx.label + ": " + pct + "%";
}
}
},
legend: {
labels: {
generateLabels: (chart) => {
const data = chart.data;
return data.labels.map((label, i) => {
const total = data.datasets[0].data
.reduce((a, b) => a + b, 0);
const pct = Math.round(
data.datasets[0].data[i] / total * 100);
return {
text: label + " (" + pct + "%)",
fillStyle: data.datasets[0].backgroundColor[i],
index: i
};
});
}
}
}
}
}
3. 分离扇区
// 点击分离效果
options: {
onClick: (event, elements, chart) => {
if (elements.length > 0) {
const idx = elements[0].index;
const ds = chart.data.datasets[0];
// 增加 offset
chart.data.datasets[0].offset = [0,0,0,0];
chart.data.datasets[0].offset[idx] = 20;
chart.update();
}
}
}
4. 圆角与边框
datasets: [{
data: [30, 40, 30],
backgroundColor: ["#e74c3c", "#f39c12", "#2ecc71"],
borderColor: "#fff",
borderWidth: 3,
borderRadius: 6, // 扇区圆角
hoverOffset: 10 // 悬停分离距离
}]
Chart.js 折线图
Chart.js 折线图
1. 基本折线图
<canvas id="lineChart"></canvas>
<script>
new Chart(document.getElementById("lineChart"), {
type: "line",
data: {
labels: ["1月", "2月", "3月", "4月", "5月", "6月"],
datasets: [{
label: "气温",
data: [5, 8, 12, 18, 24, 28],
borderColor: "#e74c3c",
backgroundColor: "rgba(231,76,60,0.1)",
fill: true, // 填充面积
tension: 0.4, // 曲线平滑度
pointRadius: 4,
pointBackgroundColor: "#e74c3c"
}]
},
options: {
responsive: true,
scales: {
y: { beginAtZero: true }
}
}
});
</script>
2. 平滑曲线
datasets: [{
data: [10, 25, 15, 30, 20, 35],
tension: 0.4 // 0=直线, 0.4=平滑曲线
}]
// 或者用 spline 效果
datasets: [{
data: [...],
cubicInterpolationMode: "monotone" // 自然平滑
}]
3. 面积图
datasets: [{
label: "访问量",
data: [100, 150, 120, 180, 160, 220],
fill: true, // 填充面积
backgroundColor: (context) => {
// 渐变填充
const { ctx, chartArea } = context.chart;
if (!chartArea) return "rgba(52,152,219,0.3)";
const grad = ctx.createLinearGradient(
0, chartArea.top, 0, chartArea.bottom);
grad.addColorStop(0, "rgba(52,152,219,0.6)");
grad.addColorStop(1, "rgba(52,152,219,0.05)");
return grad;
}
}]
4. 多线对比
datasets: [
{
label: "2025年",
data: [100, 120, 110, 140, 130, 160],
borderColor: "#3498db",
tension: 0.4
},
{
label: "2026年",
data: [120, 140, 130, 160, 150, 190],
borderColor: "#2ecc71",
borderDash: [5, 5], // 虚线
tension: 0.4
}
]
5. 数据点标签
// 需要 datalabels 插件
npm install chartjs-plugin-datalabels
import ChartDataLabels from "chartjs-plugin-datalabels";
Chart.register(ChartDataLabels);
options: {
plugins: {
datalabels: {
display: true,
anchor: "end",
align: "top",
font: { size: 11 },
formatter: (value) => value + "°"
}
}
}
Chart.js 混合图
Chart.js 混合图
1. 柱状+折线混合
<canvas id="mixedChart"></canvas>
<script>
new Chart(document.getElementById("mixedChart"), {
data: {
labels: ["Q1", "Q2", "Q3", "Q4"],
datasets: [
{
type: "bar", // 柱状
label: "销售额",
data: [120, 150, 130, 180],
backgroundColor: "rgba(52,152,219,0.7)"
},
{
type: "line", // 折线
label: "利润率",
data: [20, 25, 18, 30],
borderColor: "#e74c3c",
tension: 0.4,
yAxisID: "y2" // 第二 Y 轴
}
]
},
options: {
scales: {
y: {
type: "linear",
position: "left",
title: { display: true, text: "销售额" }
},
y2: {
type: "linear",
position: "right",
title: { display: true, text: "利润率(%)" },
grid: { drawOnChartArea: false }
}
}
}
});
</script>
2. 柱状+面积混合
datasets: [
{
type: "bar",
label: "预算",
data: [50, 60, 55, 70],
backgroundColor: "rgba(243,156,18,0.6)"
},
{
type: "line",
label: "实际",
data: [48, 65, 50, 75],
fill: true,
backgroundColor: "rgba(46,204,113,0.2)",
borderColor: "#2ecc71",
tension: 0.4
}
]
3. 混合图配置要点
// 1. datasets 中指定 type
// 2. 双轴用 yAxisID / xAxisID 关联
// 3. 每轴独立配置 title、min/max
// 4. grid 可关闭避免重叠线
options: {
scales: {
y: {
type: "linear",
beginAtZero: true
},
y2: {
type: "linear",
position: "right",
grid: { drawOnChartArea: false },
min: 0,
max: 100
}
}
}
4. 混合图应用场景
- 销量 + 增长率
- 预算 vs 实际
- 温度 + 湿度
- 访问量 + 转化率
Chart.js 极地图
Chart.js 极地图
1. 基本极地图
<canvas id="polarChart"></canvas>
<script>
new Chart(document.getElementById("polarChart"), {
type: "polarArea",
data: {
labels: ["速度", "可靠性", "舒适度", "性价比", "油耗"],
datasets: [{
data: [8, 9, 7, 6, 8],
backgroundColor: [
"rgba(52,152,219,0.7)",
"rgba(46,204,113,0.7)",
"rgba(243,156,18,0.7)",
"rgba(155,89,182,0.7)",
"rgba(231,76,60,0.7)"
],
borderWidth: 2,
borderColor: "#fff"
}]
},
options: {
scales: {
r: { // 半径轴
beginAtZero: true,
max: 10
}
}
}
});
</script>
2. 样式配置
options: {
scales: {
r: {
ticks: {
display: true,
stepSize: 2,
backdropColor: "transparent"
},
grid: { color: "#e0e0e0" }
}
},
plugins: {
legend: {
position: "bottom"
},
tooltip: {
callbacks: {
label: (ctx) => ctx.label + ": " +
ctx.parsed.r + " 分"
}
}
}
}
3. 动画效果
options: {
animation: {
animateRotate: true,
animateScale: true
}
}
Chart.js 雷达图
Chart.js 雷达图
1. 基本雷达图
<canvas id="radarChart"></canvas>
<script>
new Chart(document.getElementById("radarChart"), {
type: "radar",
data: {
labels: ["技术", "沟通", "管理", "创新", "执行力", "学习"],
datasets: [
{
label: "张三",
data: [8, 6, 5, 7, 9, 8],
borderColor: "#3498db",
backgroundColor: "rgba(52,152,219,0.2)",
pointBackgroundColor: "#3498db"
},
{
label: "李四",
data: [6, 8, 7, 5, 6, 7],
borderColor: "#e74c3c",
backgroundColor: "rgba(231,76,60,0.2)",
pointBackgroundColor: "#e74c3c"
}
]
},
options: {
scales: {
r: {
beginAtZero: true,
max: 10,
ticks: { stepSize: 2 }
}
},
plugins: {
legend: { position: "top" }
}
}
});
</script>
2. 雷达图特性
# 适合多维对比
# - 能力评估
# - 产品多维对比
# - 用户体验评分
options: {
scales: {
r: {
angleLines: { display: true },
grid: { circular: true }, // 圆形网格
pointLabels: {
font: { size: 12 },
color: "#333"
}
}
},
elements: {
line: { borderWidth: 2, tension: 0.2 },
point: { radius: 4 }
}
}
3. 填充透明度
datasets: [{
data: [8, 6, 5, 7, 9, 8],
backgroundColor: "rgba(52,152,219,0.15)",
borderColor: "#3498db",
pointRadius: 5,
pointHoverRadius: 8,
fill: true
}]
Chart.js 散点图
Chart.js 散点图
1. 基本散点图
<canvas id="scatterChart"></canvas>
<script>
new Chart(document.getElementById("scatterChart"), {
type: "scatter",
data: {
datasets: [{
label: "数据点",
data: [
{ x: 1, y: 3 },
{ x: 2, y: 5 },
{ x: 3, y: 4 },
{ x: 4, y: 8 },
{ x: 5, y: 6 }
],
backgroundColor: "rgba(52,152,219,0.7)",
pointRadius: 5
}]
},
options: {
scales: {
x: {
type: "linear", // 数值轴
position: "bottom",
title: { display: true, text: "X 值" }
},
y: {
beginAtZero: true,
title: { display: true, text: "Y 值" }
}
}
}
});
</script>
2. 分组散点
datasets: [
{
label: "组A",
data: [{x:1,y:2},{x:2,y:3},{x:3,y:5}],
backgroundColor: "#3498db"
},
{
label: "组B",
data: [{x:2,y:1},{x:3,y:2},{x:4,y:4}],
backgroundColor: "#e74c3c"
}
]
3. 拟合趋势线
// 手动计算线性回归并叠加
const points = [{x:1,y:3},{x:2,y:5},{x:3,y:4},{x:4,y:8}];
// 最小二乘
const n = points.length;
let sx=0, sy=0, sxy=0, sxx=0;
points.forEach(p => {
sx += p.x; sy += p.y;
sxy += p.x * p.y; sxx += p.x * p.x;
});
const slope = (n*sxy - sx*sy) / (n*sxx - sx*sx);
const intercept = (sy - slope*sx) / n;
const trend = [
{x: points[0].x, y: slope*points[0].x + intercept},
{x: points[n-1].x, y: slope*points[n-1].x + intercept}
];
datasets: [
{ label: "数据", data: points, type: "scatter" },
{
label: "趋势线",
data: trend,
type: "line",
borderColor: "#e74c3c",
borderDash: [5,5],
pointRadius: 0
}
]
Chart.js 总结与资源
Chart.js 总结与资源
1. 核心知识回顾
- 核心结构:type + data(labels/datasets) + options
- 8 种图表:bar、line、pie、doughnut、radar、polarArea、scatter、bubble + 混合
- 响应式:responsive + maintainAspectRatio 控制
- 动画:animation 配置时长与缓动
- 交互:onClick、tooltip callbacks、datalabels 插件
2. 常用配置速查
# 标题/图例/提示
plugins: {
title: { display: true, text: "..." },
legend: { position: "top|bottom|left|right" },
tooltip: { enabled: true, callbacks: {...} }
}
# 坐标轴
scales: {
x: { title: {...}, stacked: true },
y: { beginAtZero: true, title: {...} }
}
# 数据集常用属性
label / data / backgroundColor / borderColor
borderWidth / tension / fill / pointRadius / stack
3. 常用插件
chartjs-plugin-datalabels 数据标签 chartjs-plugin-zoom 缩放/平移 chartjs-plugin-annotation 注解线/区域 chartjs-plugin-labels 饼图标签 chartjs-chart-geo 地图图表 chartjs-chart-treemap 树状图 chartjs-chart-boxplot 箱线图
4. 官方资源
官网: chartjs.org GitHub: github.com/chartjs/Chart.js 示例库: chartjs.org/docs/latest/samples API 文档: chartjs.org/docs/latest Vue 封装: vue-chartjs React 封装: react-chartjs-2
5. 最佳实践
- 用容器包裹 canvas 并设置高度,避免变形
- 大数据量考虑采样或改用 WebGL 图表
- 移动端控制点密度与标签显示
- 颜色使用语义化配色,保持一致性
- 图表销毁时调用 destroy() 防止内存泄漏
Chart.js 上手快、文档好,是前端数据可视化的理想起点。掌握后可根据需求迁移到 ECharts(功能更强)或 D3(定制化最高)。
第 1 / 13 节