ECharts 数据格式规范完全指南
文档类型: 深度技术文档
难度等级: ⭐⭐
源码版本: ECharts 5.x
本文行数: 约550行
📋 目录
🎯 基础数据格式
一维数组 - 最简单形式
typescript
const option = {
xAxis: {
data: ['周一', '周二', '周三', '周四', '周五']
},
yAxis: {},
series: [{
type: 'bar',
data: [120, 200, 150, 80, 70] // 一维数组
}]
};1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
适用场景: 柱状图、折线图等简单图表
优点: 简洁直观
缺点: 无法携带额外信息
带名称的一维数组
typescript
series: [{
type: 'pie',
data: [
{ value: 335, name: '直接访问' },
{ value: 310, name: '邮件营销' },
{ value: 234, name: '联盟广告' }
]
}]1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
适用场景: 饼图、雷达图
优点: 每个值都有标签
📊 二维数组格式
基础二维数组
typescript
series: [{
type: 'scatter',
data: [
[10, 20], // [x, y]
[30, 40],
[50, 60],
[70, 80]
]
}]1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
坐标映射:
- 散点图:
[x, y] - K线图:
[open, close, lowest, highest] - 热力图:
[x, y, value]
三维及以上数组
typescript
// 气泡图 - [x, y, size]
series: [{
type: 'scatter',
data: [
[10, 20, 30], // x=10, y=20, 气泡大小=30
[40, 50, 60],
[70, 80, 90]
],
symbolSize: (data: number[]) => {
return data[2]; // 使用第三个维度作为大小
}
}]
// 带颜色映射 - [x, y, value, category]
series: [{
type: 'scatter',
data: [
[10, 20, 85, 1], // category=1
[40, 50, 92, 2], // category=2
[70, 80, 78, 1]
],
encode: {
x: 0, // 第一个维度映射到x轴
y: 1, // 第二个维度映射到y轴
value: 2, // 第三个维度作为值
tooltip: [0, 1, 2, 3] // tooltip显示所有维度
}
}]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
🎨 对象数组格式
带样式的对象数组
typescript
series: [{
type: 'bar',
data: [
120, // 普通数值
{
value: 200,
itemStyle: {
color: '#ff0000', // 单独设置颜色
borderWidth: 2
},
label: {
show: true,
formatter: '{c}万'
},
emphasis: {
itemStyle: {
color: '#00ff00' // 悬停时变色
}
}
},
150,
80
]
}]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
应用场景:
- 突出显示特定数据点
- 异常值高亮
- 阈值标记
带链接的对象数组
typescript
series: [{
type: 'pie',
data: [
{
value: 335,
name: '直接访问',
link: 'https://example.com/direct',
itemStyle: { /* ... */ }
},
{
value: 310,
name: '邮件营销',
link: 'https://example.com/email'
}
]
}]
// 点击跳转
chart.on('click', (params: any) => {
if (params.data.link) {
window.open(params.data.link);
}
});1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
📦 dataset数据集格式
基础dataset用法
typescript
const option = {
legend: {},
tooltip: {},
dataset: {
// 提供一份数据
source: [
['product', '2015', '2016', '2017'],
['Matcha Latte', 43.3, 85.8, 93.7],
['Milk Tea', 83.1, 73.4, 55.1],
['Cheese Cocoa', 86.4, 65.2, 82.5],
['Walnut Brownie', 72.4, 53.9, 39.1]
]
},
xAxis: { type: 'category' },
yAxis: {},
// 多个系列自动从dataset读取
series: [
{ type: 'bar' },
{ type: 'bar' },
{ type: 'bar' }
]
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
优点:
- ✅ 数据与配置分离
- ✅ 多个系列共享数据源
- ✅ 便于动态更新
dataset行列映射
typescript
const option = {
dataset: {
source: [
['月份', '销售额', '利润', '成本'],
['1月', 100, 30, 70],
['2月', 120, 35, 85],
['3月', 150, 45, 105]
]
},
series: [
{
type: 'bar',
// 指定读取第二列(销售额)
encode: {
x: '月份',
y: '销售额'
}
},
{
type: 'line',
// 指定读取第三列(利润)
encode: {
x: '月份',
y: '利润'
}
}
]
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
dataset transform数据转换
typescript
const option = {
dataset: [
{
// 原始数据
source: [
['产品', '销量', '价格'],
['产品A', 100, 50],
['产品B', 150, 80],
['产品C', 80, 120]
]
},
{
// 转换: 按销量排序
transform: {
type: 'sort',
config: { dimension: '销量', order: 'desc' }
}
}
],
xAxis: { type: 'category' },
yAxis: {},
series: {
type: 'bar',
datasetIndex: 1 // 使用转换后的数据
}
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
内置转换器:
filter: 过滤数据sort: 排序aggregate: 聚合统计boxplot: 箱线图统计
🎭 特殊图表数据格式
K线图数据
typescript
series: [{
type: 'candlestick',
data: [
// [开盘价, 收盘价, 最低价, 最高价]
[20, 30, 10, 35],
[30, 25, 22, 32],
[25, 35, 23, 38]
]
}]1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
盒须图(箱线图)数据
typescript
series: [{
type: 'boxplot',
data: [
// [min, Q1, median, Q3, max]
[10, 20, 30, 40, 50],
[15, 25, 35, 45, 55],
[12, 22, 32, 42, 52]
]
}]1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
桑基图数据
typescript
series: [{
type: 'sankey',
data: [
{ name: '源头A' },
{ name: '中间B' },
{ name: '目标C' }
],
links: [
{ source: '源头A', target: '中间B', value: 100 },
{ source: '中间B', target: '目标C', value: 80 }
]
}]1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
关系图(Graph)数据
typescript
series: [{
type: 'graph',
layout: 'force',
data: [
{ name: '节点1', value: 10, category: 0 },
{ name: '节点2', value: 20, category: 1 },
{ name: '节点3', value: 15, category: 0 }
],
links: [
{ source: '节点1', target: '节点2', value: 5 },
{ source: '节点2', target: '节点3', value: 8 }
],
categories: [
{ name: '类别A' },
{ name: '类别B' }
]
}]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
地图数据
typescript
series: [{
type: 'map',
map: 'china',
data: [
{ name: '北京', value: 100 },
{ name: '上海', value: 120 },
{ name: '广东', value: 150 },
{ name: '浙江', value: 90 }
]
}]1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
🔄 数据转换最佳实践
从API获取数据并转换
typescript
interface ApiResponse {
code: number;
data: Array<{
date: string;
sales: number;
profit: number;
}>;
}
async function loadChartData(): Promise<void> {
const response = await fetch('/api/sales');
const result: ApiResponse = await response.json();
// 转换为ECharts格式
const dates = result.data.map(item => item.date);
const salesData = result.data.map(item => item.sales);
const profitData = result.data.map(item => item.profit);
chart.setOption({
xAxis: {
data: dates
},
series: [
{
name: '销售额',
type: 'bar',
data: salesData
},
{
name: '利润',
type: 'line',
data: profitData
}
]
});
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
使用dataset简化多系列
typescript
async function loadChartDataWithDataset(): Promise<void> {
const response = await fetch('/api/sales');
const result: ApiResponse = await response.json();
// 直接转换为dataset格式
const tableData = [
['date', 'sales', 'profit'],
...result.data.map(item => [item.date, item.sales, item.profit])
];
chart.setOption({
dataset: {
source: tableData
},
xAxis: { type: 'category' },
yAxis: {},
series: [
{ type: 'bar' }, // 自动读取第二列
{ type: 'line' } // 自动读取第三列
]
});
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
实时数据流处理
typescript
class RealtimeDataManager {
private data: number[][] = [];
private maxPoints = 100;
addPoint(x: number, y: number) {
this.data.push([x, y]);
// 保持数据长度
if (this.data.length > this.maxPoints) {
this.data.shift();
}
// 更新图表
chart.setOption({
series: [{
data: this.data
}]
});
}
}
// 使用
const manager = new RealtimeDataManager();
// WebSocket接收数据
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
manager.addPoint(data.x, data.y);
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
🎯 数据格式选择决策树
📊 性能对比
| 数据格式 | 适用数据量 | 内存占用 | 渲染速度 |
|---|---|---|---|
| 一维数组 | < 10000 | 低 | 快 |
| 二维数组 | < 50000 | 中 | 中 |
| 对象数组 | < 10000 | 高 | 慢 |
| dataset | < 100000 | 低 | 快 |
建议:
- 大数据量优先使用
dataset - 需要自定义样式时使用对象数组
- 简单场景使用一维数组
🔗 相关资源
上一篇: 混合图表-(柱+折线).md)
下一篇: encode映射机制
