Chart.js 基础使用 #

创建第一个图表 #

最简单的图表 #

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>我的第一个图表</title>
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
  <div style="width: 600px; height: 400px;">
    <canvas id="myChart"></canvas>
  </div>

  <script>
    const ctx = document.getElementById('myChart');
    
    new Chart(ctx, {
      type: 'bar',
      data: {
        labels: ['红色', '蓝色', '黄色', '绿色', '紫色', '橙色'],
        datasets: [{
          label: '投票数',
          data: [12, 19, 3, 5, 2, 3]
        }]
      }
    });
  </script>
</body>
</html>

图表配置结构 #

text
┌─────────────────────────────────────────────────────────────┐
│                    Chart.js 配置结构                          │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  new Chart(ctx, {                                           │
│    type: '图表类型',     ← bar, line, pie 等                │
│    data: {               ← 数据配置                          │
│      labels: [],                                             │
│      datasets: []                                            │
│    },                                                        │
│    options: {            ← 选项配置                          │
│      responsive: true,                                       │
│      plugins: {},                                            │
│      scales: {}                                              │
│    }                                                         │
│  });                                                         │
│                                                              │
└─────────────────────────────────────────────────────────────┘

数据结构 #

基本数据结构 #

javascript
const data = {
  // 标签数组:X 轴的刻度标签
  labels: ['一月', '二月', '三月', '四月', '五月', '六月'],
  
  // 数据集数组:可以包含多个数据集
  datasets: [{
    // 数据集标签
    label: '2024年销售额',
    
    // 数据数组:与 labels 一一对应
    data: [65, 59, 80, 81, 56, 55],
    
    // 样式配置
    backgroundColor: 'rgba(75, 192, 192, 0.5)',
    borderColor: 'rgba(75, 192, 192, 1)',
    borderWidth: 1
  }]
};

多数据集 #

javascript
const data = {
  labels: ['一月', '二月', '三月', '四月', '五月', '六月'],
  datasets: [
    {
      label: '2023年',
      data: [65, 59, 80, 81, 56, 55],
      backgroundColor: 'rgba(255, 99, 132, 0.5)',
      borderColor: 'rgba(255, 99, 132, 1)'
    },
    {
      label: '2024年',
      data: [28, 48, 40, 19, 86, 27],
      backgroundColor: 'rgba(54, 162, 235, 0.5)',
      borderColor: 'rgba(54, 162, 235, 1)'
    }
  ]
};

对象数组数据 #

javascript
const data = {
  datasets: [{
    label: '散点数据',
    data: [
      { x: 10, y: 20 },
      { x: 15, y: 25 },
      { x: 20, y: 30 },
      { x: 25, y: 28 }
    ],
    backgroundColor: 'rgba(75, 192, 192, 0.5)'
  }]
};

气泡图数据 #

javascript
const data = {
  datasets: [{
    label: '气泡图',
    data: [
      { x: 10, y: 20, r: 10 },
      { x: 15, y: 25, r: 15 },
      { x: 20, y: 30, r: 5 }
    ]
  }]
};

图表类型 #

8 种基本图表 #

javascript
// 1. 柱状图
new Chart(ctx, { type: 'bar', data, options });

// 2. 折线图
new Chart(ctx, { type: 'line', data, options });

// 3. 饼图
new Chart(ctx, { type: 'pie', data, options });

// 4. 环形图
new Chart(ctx, { type: 'doughnut', data, options });

// 5. 雷达图
new Chart(ctx, { type: 'radar', data, options });

// 6. 极坐标图
new Chart(ctx, { type: 'polarArea', data, options });

// 7. 气泡图
new Chart(ctx, { type: 'bubble', data, options });

// 8. 散点图
new Chart(ctx, { type: 'scatter', data, options });

图表类型变体 #

javascript
// 水平柱状图
new Chart(ctx, {
  type: 'bar',
  data: data,
  options: {
    indexAxis: 'y'
  }
});

// 堆叠柱状图
new Chart(ctx, {
  type: 'bar',
  data: data,
  options: {
    scales: {
      x: { stacked: true },
      y: { stacked: true }
    }
  }
});

基本配置选项 #

响应式配置 #

javascript
const options = {
  // 响应式:自动调整大小
  responsive: true,
  
  // 保持宽高比
  maintainAspectRatio: true,
  
  // 宽高比(当 maintainAspectRatio 为 true 时生效)
  aspectRatio: 2,
  
  // 调整大小延迟
  resizeDelay: 0,
  
  // 容器
  resizeObserver: true
};

标题配置 #

javascript
const options = {
  plugins: {
    title: {
      // 是否显示标题
      display: true,
      
      // 标题文本
      text: '月度销售报告',
      
      // 位置:'top', 'bottom', 'left', 'right'
      position: 'top',
      
      // 对齐方式:'start', 'center', 'end'
      align: 'center',
      
      // 字体配置
      font: {
        family: 'Arial',
        size: 16,
        weight: 'bold',
        style: 'normal'
      },
      
      // 颜色
      color: '#333',
      
      // 内边距
      padding: {
        top: 10,
        bottom: 10
      }
    }
  }
};

图例配置 #

javascript
const options = {
  plugins: {
    legend: {
      // 是否显示图例
      display: true,
      
      // 位置:'top', 'bottom', 'left', 'right'
      position: 'top',
      
      // 对齐方式
      align: 'center',
      
      // 最大宽度/高度
      maxWidth: 200,
      maxHeight: 100,
      
      // 是否可点击切换显示
      onClick: (e, legendItem, legend) => {
        const index = legendItem.datasetIndex;
        const ci = legend.chart;
        const meta = ci.getDatasetMeta(index);
        meta.hidden = meta.hidden === null ? !ci.data.datasets[index].hidden : null;
        ci.update();
      },
      
      // 标签配置
      labels: {
        // 字体
        font: {
          size: 12
        },
        // 颜色
        color: '#666',
        // 使用数据集样式
        usePointStyle: true,
        // 盒子尺寸
        boxWidth: 40,
        boxHeight: 12,
        // 内边距
        padding: 20
      }
    }
  }
};

提示框配置 #

javascript
const options = {
  plugins: {
    tooltip: {
      // 是否启用
      enabled: true,
      
      // 模式:'point', 'nearest', 'index', 'dataset', 'x', 'y'
      mode: 'index',
      
      // 是否相交
      intersect: false,
      
      // 背景色
      backgroundColor: 'rgba(0, 0, 0, 0.8)',
      
      // 标题字体
      titleFont: {
        size: 14,
        weight: 'bold'
      },
      
      // 正文字体
      bodyFont: {
        size: 12
      },
      
      // 内边距
      padding: 10,
      
      // 圆角
      cornerRadius: 4,
      
      // 自定义回调
      callbacks: {
        title: function(context) {
          return '标题: ' + context[0].label;
        },
        label: function(context) {
          return context.dataset.label + ': ' + context.parsed.y;
        }
      }
    }
  }
};

坐标轴配置 #

基本坐标轴 #

javascript
const options = {
  scales: {
    // X 轴
    x: {
      // 是否显示
      display: true,
      
      // 标题
      title: {
        display: true,
        text: '月份'
      },
      
      // 刻度配置
      ticks: {
        color: '#666',
        font: { size: 12 }
      },
      
      // 网格线
      grid: {
        display: true,
        color: '#eee'
      }
    },
    
    // Y 轴
    y: {
      display: true,
      title: {
        display: true,
        text: '销售额'
      },
      ticks: {
        color: '#666'
      },
      grid: {
        color: '#eee'
      }
    }
  }
};

Y 轴范围 #

javascript
const options = {
  scales: {
    y: {
      // 最小值
      min: 0,
      
      // 最大值
      max: 100,
      
      // 从零开始
      beginAtZero: true
    }
  }
};

多 Y 轴 #

javascript
const options = {
  scales: {
    y: {
      type: 'linear',
      display: true,
      position: 'left',
      title: {
        display: true,
        text: '销售额'
      }
    },
    y1: {
      type: 'linear',
      display: true,
      position: 'right',
      title: {
        display: true,
        text: '增长率'
      },
      grid: {
        drawOnChartArea: false
      }
    }
  }
};

// 数据集指定使用的轴
const data = {
  datasets: [
    {
      label: '销售额',
      data: [65, 59, 80],
      yAxisID: 'y'
    },
    {
      label: '增长率',
      data: [10, 15, 20],
      yAxisID: 'y1'
    }
  ]
};

图表实例操作 #

获取图表实例 #

javascript
// 创建图表并保存实例
const myChart = new Chart(ctx, config);

// 获取图表实例
const chartInstance = Chart.getChart('myChart');

更新数据 #

javascript
const myChart = new Chart(ctx, config);

// 方式一:直接修改数据
myChart.data.datasets[0].data = [1, 2, 3, 4, 5];
myChart.update();

// 方式二:添加数据
myChart.data.labels.push('七月');
myChart.data.datasets[0].data.push(70);
myChart.update();

// 方式三:移除数据
myChart.data.labels.pop();
myChart.data.datasets[0].data.pop();
myChart.update();

更新配置 #

javascript
// 更新选项
myChart.options.plugins.title.text = '新标题';
myChart.update();

// 更新数据集
myChart.data.datasets[0].backgroundColor = 'red';
myChart.update();

更新模式 #

javascript
// 默认模式:带动画
myChart.update();

// 指定模式
myChart.update('active');    // 动画
myChart.update('resize');    // 调整大小
myChart.update('none');      // 无动画
myChart.update('default');   // 默认动画

销毁图表 #

javascript
// 销毁图表实例
myChart.destroy();

// 清空画布
myChart.clear();

// 重置图表
myChart.reset();

获取数据 #

javascript
// 获取数据集
const datasets = myChart.data.datasets;

// 获取特定数据点的值
const dataPoint = myChart.getDatasetMeta(0).data[0];

// 获取图表区域
const chartArea = myChart.chartArea;

样式定制 #

颜色配置 #

javascript
const data = {
  datasets: [{
    // 单色
    backgroundColor: 'rgba(75, 192, 192, 0.5)',
    borderColor: 'rgba(75, 192, 192, 1)',
    
    // 多色(数组)
    backgroundColor: [
      'rgba(255, 99, 132, 0.5)',
      'rgba(54, 162, 235, 0.5)',
      'rgba(255, 206, 86, 0.5)'
    ],
    
    // 渐变色
    backgroundColor: function(context) {
      const chart = context.chart;
      const { ctx, chartArea } = chart;
      if (!chartArea) return;
      const gradient = ctx.createLinearGradient(0, chartArea.bottom, 0, chartArea.top);
      gradient.addColorStop(0, 'rgba(75, 192, 192, 0.5)');
      gradient.addColorStop(1, 'rgba(255, 99, 132, 0.5)');
      return gradient;
    }
  }]
};

边框样式 #

javascript
const data = {
  datasets: [{
    borderColor: 'blue',
    borderWidth: 2,
    borderDash: [5, 5],        // 虚线
    borderDashOffset: 0,
    borderRadius: 5,           // 圆角
    borderSkipped: false       // 不跳过任何边
  }]
};

点样式 #

javascript
const data = {
  datasets: [{
    // 点样式:'circle', 'cross', 'crossRot', 'dash', 'line', 'rect', 'rectRounded', 'rectRot', 'star', 'triangle'
    pointStyle: 'circle',
    
    // 点半径
    pointRadius: 5,
    
    // 悬停点半径
    pointHoverRadius: 8,
    
    // 点颜色
    pointBackgroundColor: 'rgba(75, 192, 192, 1)',
    pointBorderColor: '#fff',
    pointBorderWidth: 2,
    
    // 悬停颜色
    pointHoverBackgroundColor: '#fff',
    pointHoverBorderColor: 'rgba(75, 192, 192, 1)'
  }]
};

事件处理 #

基本事件 #

javascript
const options = {
  // 点击事件
  onClick: (event, elements, chart) => {
    if (elements.length > 0) {
      const element = elements[0];
      console.log('点击了第', element.index, '个数据点');
    }
  },
  
  // 悬停事件
  onHover: (event, elements, chart) => {
    event.native.target.style.cursor = elements.length ? 'pointer' : 'default';
  },
  
  // 离开事件
  onLeave: (event, elements, chart) => {
    event.native.target.style.cursor = 'default';
  }
};

插件事件 #

javascript
const options = {
  plugins: {
    legend: {
      onClick: (e, legendItem, legend) => {
        console.log('点击了图例:', legendItem.text);
      }
    },
    tooltip: {
      onShow: (tooltip) => {
        console.log('显示提示框');
      },
      onHide: (tooltip) => {
        console.log('隐藏提示框');
      }
    }
  }
};

实用示例 #

动态更新图表 #

javascript
const ctx = document.getElementById('myChart');
const myChart = new Chart(ctx, {
  type: 'line',
  data: {
    labels: [],
    datasets: [{
      label: '实时数据',
      data: [],
      borderColor: 'rgb(75, 192, 192)',
      tension: 0.4
    }]
  },
  options: {
    animation: {
      duration: 300
    }
  }
});

// 模拟实时数据
setInterval(() => {
  const now = new Date();
  const timeLabel = now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds();
  const value = Math.random() * 100;
  
  // 添加新数据
  myChart.data.labels.push(timeLabel);
  myChart.data.datasets[0].data.push(value);
  
  // 保持最多 10 个数据点
  if (myChart.data.labels.length > 10) {
    myChart.data.labels.shift();
    myChart.data.datasets[0].data.shift();
  }
  
  myChart.update('none');
}, 1000);

导出图表为图片 #

javascript
function exportChart(chart) {
  const link = document.createElement('a');
  link.download = 'chart.png';
  link.href = chart.toBase64Image();
  link.click();
}

// 使用
document.getElementById('exportBtn').addEventListener('click', () => {
  exportChart(myChart);
});

响应式图表 #

javascript
const options = {
  responsive: true,
  maintainAspectRatio: false,
  plugins: {
    title: {
      display: true,
      text: '响应式图表'
    }
  },
  scales: {
    x: {
      ticks: {
        // 小屏幕时隐藏标签
        display: window.innerWidth > 400
      }
    }
  }
};

// 监听窗口大小变化
window.addEventListener('resize', () => {
  myChart.options.scales.x.ticks.display = window.innerWidth > 400;
  myChart.resize();
});

最佳实践 #

1. 使用变量存储配置 #

javascript
// 好的做法
const chartData = {
  labels: ['A', 'B', 'C'],
  datasets: [{ data: [1, 2, 3] }]
};

const chartOptions = {
  responsive: true
};

const myChart = new Chart(ctx, {
  type: 'bar',
  data: chartData,
  options: chartOptions
});

2. 销毁旧图表 #

javascript
// 在创建新图表前销毁旧图表
let myChart = null;

function createChart(data) {
  if (myChart) {
    myChart.destroy();
  }
  myChart = new Chart(ctx, {
    type: 'bar',
    data: data
  });
}

3. 使用 TypeScript 类型 #

typescript
import { ChartConfiguration } from 'chart.js';

const config: ChartConfiguration = {
  type: 'bar',
  data: {
    labels: ['A', 'B', 'C'],
    datasets: [{ data: [1, 2, 3] }]
  }
};

下一步 #

现在你已经掌握了 Chart.js 的基础使用,接下来学习 配置选项,深入了解各种配置参数!

最后更新:2026-03-28