ECharts
JavaScript 数据可视化图表库 —— 开箱即用、交互丰富、高性能
官网:https://echarts.apache.org/zh/index.html
示例:https://echarts.apache.org/examples/zh/
GitHub:https://github.com/apache/echarts
发展历史
ECharts 是由百度前端团队开发的纯 JavaScript 图表库,后捐赠给 Apache 基金会:
| 时期 | 版本 | 时间 | 里程碑 |
|---|---|---|---|
| 初始发布 | ECharts 1.0 | 2013 | 百度前端数据可视化团队发布,基于 Canvas,支持 6 种图表类型 |
| 快速发展 | ECharts 2.0 | 2014 | 引入拖拽重计算、数据视图、多系列联动等交互特性 |
| 架构重构 | ECharts 3.0 | 2016 | 全新架构,体积大幅减小(从 800KB → 400KB),引入 ZRender 2.0 渲染层 |
| 捐赠 Apache | ECharts 4.0 | 2018 | 正式捐赠给 Apache 基金会,支持更多图表类型,加强数据集(dataset)支持 |
| 重大升级 | ECharts 5.0 | 2021 | 全新的动态样式、增强的交互体验、更好的无障碍支持(aria) |
| 持续迭代 | ECharts 5.5+ | 2024+ | 优化渲染性能,增强国际化、自定义系列能力 |
核心特性
| 特性 | 说明 |
|---|---|
| 图表类型丰富 | 20+ 内置图表类型,覆盖常见可视化场景 |
| 交互丰富 | 缩放、拖拽、数据筛选、tooltip、联动高亮 |
| 大数据量 | 通过 Canvas 渲染,可流畅展示十万级数据点 |
| 跨平台 | 纯 JavaScript,兼容所有现代浏览器,支持移动端触摸事件 |
| 主题系统 | 内置亮/暗主题,支持自定义主题注册 |
| 响应式 | 容器尺寸变化时自动重绘 |
| 国际化 | 内置多语言标签包 |
| 无障碍 | 支持 ARIA 标签,适配屏幕阅读器 |
应用场景
| 场景 | 说明 | 常用图表 |
|---|---|---|
| 数据分析报表 | 运营数据、财务数据的趋势和对比展示 | 折线图、柱状图、饼图 |
| 实时监控大屏 | 服务器指标、业务指标的实时可视化 | 仪表盘、折线图、热力图 |
| 地理信息展示 | 区域数据分布、流量热力分布 | 地图、散点图、路径图 |
| 金融数据 | 股票行情、涨跌幅分析 | K 线图、折线图、柱状图 |
| 关系网络分析 | 社交关系、知识图谱、组织架构 | 关系图、树图、桑基图 |
| 数据挖掘展示 | 聚类结果、异常检测的可视化 | 散点图、盒须图、平行坐标系 |
| 产品运营 | 用户转化漏斗、流量分析 | 漏斗图、饼图、桑基图 |
安装
CDN 引入
html
<!-- 完整版 -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
<!-- 或从官网下载 -->
<script src="https://echarts.apache.org/zh/download.html"></script>NPM 安装
bash
npm install echarts
# yarn add echarts
# pnpm add echarts快速上手
最小示例
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ECharts 示例</title>
<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
</head>
<body>
<!-- 1. 准备容器 -->
<div id="main" style="width: 600px; height: 400px;"></div>
<script>
// 2. 初始化图表
var chart = echarts.init(document.getElementById('main'));
// 3. 配置选项
var option = {
title: {
text: '销售趋势'
},
tooltip: {
trigger: 'axis'
},
xAxis: {
type: 'category',
data: ['一月', '二月', '三月', '四月', '五月', '六月']
},
yAxis: {
type: 'value'
},
series: [{
name: '销售额',
type: 'line',
data: [820, 932, 901, 934, 1290, 1330]
}]
};
// 4. 渲染图表
chart.setOption(option);
</script>
</body>
</html>在 Node.js / SSR 中使用
javascript
// 服务端渲染(需要安装 canvas 包)
const echarts = require('echarts');
const { createCanvas } = require('canvas');
const canvas = createCanvas(800, 600);
const chart = echarts.init(canvas);
chart.setOption({
xAxis: { type: 'category', data: ['A', 'B', 'C'] },
yAxis: { type: 'value' },
series: [{ type: 'bar', data: [10, 20, 15] }]
});
// 输出为 Buffer
const buffer = canvas.toBuffer('image/png');在 Vue / React 中使用
vue
<template>
<div ref="chartRef" style="width: 100%; height: 400px;"></div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import * as echarts from 'echarts'
const chartRef = ref(null)
let chart = null
onMounted(() => {
chart = echarts.init(chartRef.value)
chart.setOption({
xAxis: { type: 'category', data: ['A', 'B', 'C'] },
yAxis: { type: 'value' },
series: [{ type: 'bar', data: [10, 20, 15] }]
})
// 响应式
window.addEventListener('resize', () => chart?.resize())
})
onUnmounted(() => {
chart?.dispose()
})
</script>图表类型
ECharts 支持 20+ 种图表,按坐标系分类:
直角坐标系(grid)
| 图表 | type 值 | dataset | 说明 |
|---|---|---|---|
| 折线图 | line | ✅ | 展示数据随时间或类别的变化趋势 |
| 柱状图 | bar | ✅ | 分类数据的大小对比 |
| 散点图 | scatter | ✅ | 展示两个变量的相关性和分布 |
| K 线图 | candlestick | ✅ | 金融数据的高低开收 |
| 箱线图(盒须图) | boxplot | ❌ | 展示数据分布的离散程度和异常值 |
| 热力图 | heatmap | ❌ | 用颜色表示数据的密度或强度 |
| 路径图 | lines | ❌ | 飞行航线、物流路径等轨迹 |
| 象形柱图 | pictorialBar | ❌ | 使用图片代替柱状条 |
极坐标系(polar)
| 图表 | type 值 | dataset | 说明 |
|---|---|---|---|
| 雷达图 | radar | ❌ | 多维度指标的综合对比 |
| 饼图 | pie | ✅ | 各部分占总体的比例 |
地理坐标系(geo)
| 图表 | type 值 | dataset | 说明 |
|---|---|---|---|
| 地图 | map | ✅ | 区域数据的地理分布 |
| 散点图(地理) | scatter | ✅ | 地理位置的标记 |
| 路径图(地理) | lines | ❌ | 地理轨迹 |
其他独立图表
| 图表 | type 值 | dataset | 说明 |
|---|---|---|---|
| 饼图 | pie | ✅ | 占比和构成分析 |
| 漏斗图 | funnel | ✅ | 流程转化率分析 |
| 仪表盘 | gauge | ❌ | 实时指标读数展示 |
| 关系图 | graph | ❌ | 节点关系网络 |
| 树图 | tree | ❌ | 树形层级结构 |
| 矩形树图 | treemap | ❌ | 占比 + 层级嵌套 |
| 旭日图 | sunburst | ❌ | 多层环形层级结构 |
| 桑基图 | sankey | ❌ | 流量/能量的流向 |
| 平行坐标系 | parallel | ✅ | 高维数据的对比分析 |
| 主题河流图 | themeRiver | ❌ | 主题随时间演变的河流图 |
| 日历坐标系 | calendar | ❌ | 日历热力图 |
| 自定义系列 | custom | ✅ | 用图形元素自由构建图表 |
核心概念
ECharts 的架构
数据(dataset / data)
│
▼
encode(数据到坐标轴的映射)
│
▼
series(图表的类型和样式配置)
│
▼
坐标系(grid / polar / geo / calendar)
│
▼
组件(title / legend / tooltip / dataZoom / visualMap)
│
▼
Canvas / SVG 渲染输出Option(配置选项)
ECharts 的所有配置都通过一个 JSON 对象(option)描述。一个完整的 option 结构:
javascript
var option = {
// ---- 全局组件 ----
title: { text: '标题' }, // 标题
legend: { data: ['系列1'] }, // 图例
tooltip: { trigger: 'axis' }, // 提示框
toolbox: { feature: {...} }, // 工具栏(保存图片、数据视图等)
dataZoom: [{...}], // 数据缩放
// ---- 坐标系 ----
xAxis: { type: 'category' }, // X 轴
yAxis: { type: 'value' }, // Y 轴
// polar: {}, // 极坐标系
// geo: {}, // 地理坐标系
// ---- 数据 ----
dataset: { source: [...] }, // 数据集(推荐)
// 或直接使用 series.data
// ---- 图表系列 ----
series: [{
name: '系列名',
type: 'line', // 图表类型
data: [...], // 数据
encode: { x: 0, y: 1 }, // 维度映射
smooth: true, // 平滑曲线
areaStyle: {} // 面积图样式
}]
};Dataset(数据集)
ECharts 4.0+ 推荐使用 dataset 来管理数据,将数据与图表配置分离:
javascript
var option = {
dataset: {
source: [
['product', '销售额', '成本', '利润'],
['一月', 820, 500, 320],
['二月', 932, 550, 382],
['三月', 901, 480, 421],
['四月', 934, 600, 334],
['五月', 1290, 800, 490],
['六月', 1330, 900, 430]
]
},
xAxis: { type: 'category' },
yAxis: { type: 'value' },
series: [
{ type: 'bar', encode: { x: 'product', y: '销售额' } },
{ type: 'bar', encode: { x: 'product', y: '成本' } },
{ type: 'line', encode: { x: 'product', y: '利润' } }
]
};dataset 的优势:
- 数据与配置分离,便于维护
- 多个 series 可以共享同一数据源
- 支持数据转换(排序、过滤等)
Encode(数据映射)
encode 用于声明 dataset 的维度如何映射到图表的视觉通道:
javascript
encode: {
x: 'product', // 映射到 X 轴(维度名)
y: '销售额', // 映射到 Y 轴
// 或使用维度索引
// x: 0,
// y: 1
}详见下方的 encode 格式 章节。
常用配置
交互组件
javascript
var option = {
// 工具栏
toolbox: {
feature: {
saveAsImage: {}, // 保存为图片
dataView: {}, // 数据视图
restore: {}, // 重置
dataZoom: {}, // 区域缩放
magicType: { // 动态类型切换
type: ['line', 'bar', 'stack']
}
}
},
// 数据缩放
dataZoom: [{
type: 'inside', // 内置滚动缩放
start: 0,
end: 100
}, {
type: 'slider', // 滑动条
start: 0,
end: 100
}],
// 视觉映射(颜色、大小等)
visualMap: {
min: 0,
max: 100,
inRange: {
color: ['#50a3ba', '#eac736', '#d94e5d']
}
}
};样式主题
javascript
// 方式一:初始化时指定主题
var chart = echarts.init(dom, 'dark'); // 内置暗色主题
// 方式二:注册自定义主题
echarts.registerTheme('myTheme', {
backgroundColor: '#f4f4f4',
color: ['#c23531', '#314656', '#61a0a8', '#d48265']
});
var chart = echarts.init(dom, 'myTheme');
// 方式三:在 option 中配置
var option = {
backgroundColor: '#f4f4f4',
color: ['#c23531', '#314656', '#61a0a8']
};动画
javascript
var option = {
animation: true,
animationDuration: 1000, // 动画时长
animationEasing: 'cubicOut', // 缓动函数
animationDelay: function (idx) {
return idx * 100; // 逐条延迟动画
}
};响应式
javascript
var chart = echarts.init(dom);
// 监听容器尺寸变化
window.addEventListener('resize', function () {
chart.resize();
});
// 指定适配后的尺寸(自定义)
chart.resize({ width: 800, height: 600 });常见图表示例
柱状图 + 折线图混搭
javascript
var option = {
tooltip: { trigger: 'axis' },
legend: { data: ['蒸发量', '降雨量', '平均温度'] },
xAxis: {
type: 'category',
data: ['一月', '二月', '三月', '四月', '五月']
},
yAxis: [
{ type: 'value', name: '水量 (ml)' },
{ type: 'value', name: '温度 (°C)' }
],
series: [
{
name: '蒸发量',
type: 'bar',
data: [2.0, 4.9, 7.0, 23.2, 25.6]
},
{
name: '降雨量',
type: 'bar',
data: [2.6, 5.9, 9.0, 26.4, 28.7]
},
{
name: '平均温度',
type: 'line',
yAxisIndex: 1,
data: [2.0, 2.2, 3.3, 4.5, 6.3]
}
]
};饼图(带图例)
javascript
var option = {
tooltip: { trigger: 'item', formatter: '{b}: {c} ({d}%)' },
legend: { orient: 'vertical', left: 'left' },
series: [{
type: 'pie',
radius: ['40%', '70%'], // 环形饼图
label: { show: true, formatter: '{b}: {d}%' },
data: [
{ value: 1048, name: '搜索引擎' },
{ value: 735, name: '直接访问' },
{ value: 580, name: '邮件营销' },
{ value: 484, name: '联盟广告' },
{ value: 300, name: '视频广告' }
]
}]
};实时折线图
javascript
var chart = echarts.init(dom);
var data = [];
// 每秒追加数据
setInterval(function () {
var now = new Date().toLocaleTimeString();
var value = Math.random() * 100;
data.push([now, value]);
// 只保留最近 20 个点
if (data.length > 20) data.shift();
chart.setOption({
xAxis: { type: 'time' },
yAxis: { type: 'value', min: 0, max: 100 },
series: [{ type: 'line', data: data, smooth: true }]
});
}, 1000);高级用法
按需加载
ECharts 5 支持 Tree Shaking,可以根据需要只引入使用的图表和组件,大幅减小打包体积:
javascript
// 只引入折线图和柱状图,不引入其他图表
import { init, use } from 'echarts/core';
import { LineChart, BarChart } from 'echarts/charts';
import { GridComponent, TooltipComponent, LegendComponent } from 'echarts/components';
import { CanvasRenderer } from 'echarts/renderers';
use([
LineChart, BarChart,
GridComponent, TooltipComponent, LegendComponent,
CanvasRenderer
]);
var chart = init(document.getElementById('main'));
chart.setOption({ /* option */ });数据转换(Data Transform)
ECharts 5.5+ 支持在 dataset 内部做数据转换,无需手动处理数据:
javascript
var option = {
dataset: [{
id: 'raw',
source: [
['product', '销售额', '成本'],
['一月', 820, 500],
['二月', 932, 550],
['三月', 901, 480]
]
}, {
id: 'sorted',
fromDatasetId: 'raw',
transform: {
type: 'sort',
config: { sortBy: '销售额', order: 'desc' }
}
}],
series: [{
type: 'bar',
datasetId: 'sorted',
encode: { x: 'product', y: '销售额' }
}]
};多图表联动
javascript
var chart1 = echarts.init(document.getElementById('chart1'));
var chart2 = echarts.init(document.getElementById('chart2'));
// chart1 的 dataZoom 变化时同步 chart2
chart1.on('dataZoom', function (params) {
chart2.dispatchAction({
type: 'dataZoom',
start: params.start,
end: params.end
});
});encode 格式
全局支持属性
在任何坐标系和系列中,都支持以下 encode 属性:
javascript
encode: {
// 在 tooltip 中显示指定维度
tooltip: ['product', 'score'],
// 使用指定维度的值作为系列名
seriesName: [1, 3],
// 数据项的唯一 ID,用于 setOption 更新时保持对应
itemId: 2,
// 数据项的名称,在饼图中显示为图例
itemName: 3,
// 数据项的组 ID,用于全局过渡动画
itemGroupId: 4,
// 子数据组 ID,用于多层下钻和聚合(v5.5.0+)
itemChildGroupId: 5
}直角坐标系
javascript
// 把维度 1、维度 5、名为 score 的维度映射到 X 轴
encode: { x: [1, 5, 'score'], y: 0 }单轴
javascript
encode: { single: 3 }地理坐标系
javascript
encode: { lng: 3, lat: 2 }无坐标系图表(饼图、漏斗图)
javascript
encode: { value: 3 }自定义系列
在自定义系列中,可将 encode 的轴设为 -1 使其不受该轴控制:
javascript
encode: { x: -1, y: 1 } // X 轴不控制此系列更新与销毁
javascript
// 增量更新(ECharts 会智能合并)
chart.setOption({
series: [{ data: newData }]
});
// 完全替换(清空旧配置)
chart.setOption(option, true);
// 获取当前配置
var currentOption = chart.getOption();
// 自适应容器
chart.resize();
// 销毁
chart.dispose();