tooltip 富文本
ECharts 提示框完全指南:自定义格式化与富文本样式
📖 概述
tooltip(提示框)是ECharts中最常用的交互组件,用于显示数据点的详细信息。ECharts 5+ 支持完整的富文本样式定制,可以创建美观、信息丰富的提示框。
核心特性:
- ✅ 字符串模板格式化
- ✅ 自定义函数格式化
- ✅ 富文本样式(rich)
- ✅ HTML内容支持
- ✅ 多系列合并显示
🔍 核心概念
1. 基础配置
javascript
tooltip: {
trigger: 'item', // 'item' | 'axis' | 'none'
formatter: '{b}: {c}' // 格式化字符串
}1
2
3
4
2
3
4
触发方式:
item: 数据项图形触发(散点图、饼图)axis: 坐标轴触发(折线图、柱状图)none: 不触发
2. 格式化器
字符串模板
javascript
formatter: '{a} <br/>{b}: {c} ({d}%)'
// 变量说明:
// {a}: 系列名
// {b}: 数据名
// {c}: 数据值
// {d}: 百分比(饼图)
// {@xxx}: 数据中的维度名(dataset)1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
函数格式化
javascript
formatter: function(params) {
if (Array.isArray(params)) {
// axis触发,多个系列
let html = `<strong>${params[0].name}</strong><br/>`;
params.forEach(param => {
html += `${param.marker}${param.seriesName}: ${param.value}<br/>`;
});
return html;
} else {
// item触发,单个系列
return `${params.name}<br/>${params.seriesName}: ${params.value}`;
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
3. 富文本样式
javascript
tooltip: {
formatter: [
'{title|{b}}',
'{hr|}',
'{label|销售额}: {value|{c}}',
'{label|增长率}: {percent|{d}%}'
].join('<br/>'),
backgroundColor: '#fff',
borderColor: '#ddd',
borderWidth: 1,
padding: [10, 15],
textStyle: {
color: '#333'
},
// 富文本样式定义
extraCssText: 'box-shadow: 0 2px 10px rgba(0,0,0,0.1);',
rich: {
title: {
fontSize: 16,
fontWeight: 'bold',
color: '#333',
lineHeight: 24,
padding: [0, 0, 5, 0]
},
hr: {
borderColor: '#ddd',
width: '100%',
borderWidth: 0.5,
height: 0
},
label: {
fontSize: 12,
color: '#666',
lineHeight: 20
},
value: {
fontSize: 14,
fontWeight: 'bold',
color: '#5470c6',
align: 'right',
padding: [0, 0, 0, 10]
},
percent: {
fontSize: 12,
color: '#91cc75',
align: 'right'
}
}
}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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
💡 使用场景
场景 1: 销售数据详细提示
javascript
const salesTooltip = {
trigger: 'axis',
backgroundColor: 'rgba(255, 255, 255, 0.95)',
borderColor: '#eee',
borderWidth: 1,
padding: [12, 16],
textStyle: {
color: '#333',
fontSize: 13
},
formatter: function(params) {
const date = params[0].name;
let html = `<div style="padding: 4px 0">`;
html += `<strong style="font-size: 14px">${date}</strong>`;
html += `</div>`;
html += `<div style="border-top: 1px solid #eee; margin: 8px 0"></div>`;
params.forEach(param => {
const color = param.color;
const name = param.seriesName;
const value = param.value.toLocaleString();
const marker = `<span style="display:inline-block;margin-right:4px;border-radius:10px;width:10px;height:10px;background-color:${color};"></span>`;
html += `<div style="margin: 6px 0">`;
html += `${marker}<span style="display:inline-block;width:60px">${name}</span>`;
html += `<span style="float:right;font-weight:bold;color:${color}">¥${value}</span>`;
html += `</div>`;
});
// 计算总计
const total = params.reduce((sum, p) => sum + p.value, 0);
html += `<div style="border-top: 1px solid #eee; margin: 8px 0"></div>`;
html += `<div style="display:flex;justify-content:space-between;font-weight:bold">`;
html += `<span>总计</span>`;
html += `<span style="color:#5470c6">¥${total.toLocaleString()}</span>`;
html += `</div>`;
return html;
}
};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
37
38
39
40
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
37
38
39
40
场景 2: K线图专业提示
javascript
const klineTooltip = {
trigger: 'axis',
axisPointer: { type: 'cross' },
backgroundColor: 'rgba(0, 0, 0, 0.8)',
borderColor: '#333',
textStyle: { color: '#fff' },
formatter: function(params) {
const ohlc = params[0].data;
const change = ohlc[1] - ohlc[0];
const changePercent = ((change / ohlc[0]) * 100).toFixed(2);
const isUp = change >= 0;
const color = isUp ? '#ef232a' : '#14b143';
let html = `<div style="padding: 8px">`;
html += `<div style="font-size: 14px;font-weight:bold;margin-bottom: 8px">${params[0].name}</div>`;
html += `<div style="display:grid;grid-template-columns: 60px 1fr;gap: 6px 12px">`;
html += `<span style="color:#999">开盘:</span><span style="text-align:right">${ohlc[0]}</span>`;
html += `<span style="color:#999">收盘:</span><span style="text-align:right;color:${color};font-weight:bold">${ohlc[1]}</span>`;
html += `<span style="color:#999">最低:</span><span style="text-align:right">${ohlc[2]}</span>`;
html += `<span style="color:#999">最高:</span><span style="text-align:right">${ohlc[3]}</span>`;
html += `</div>`;
html += `<div style="margin-top: 8px;padding-top: 8px;border-top: 1px solid #444;text-align:center">`;
html += `<span style="color:${color};font-size: 16px;font-weight:bold">`;
html += `${isUp ? '+' : ''}${change.toFixed(2)} (${isUp ? '+' : ''}${changePercent}%)`;
html += `</span>`;
html += `</div>`;
html += `</div>`;
return html;
}
};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
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
场景 3: 地图区域提示
javascript
const mapTooltip = {
trigger: 'item',
backgroundColor: 'rgba(255, 255, 255, 0.95)',
borderColor: '#ddd',
borderWidth: 1,
padding: 0,
formatter: function(params) {
const data = params.data;
if (!data) return '';
return `
<div style="width: 200px">
<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);padding: 12px;color: #fff">
<div style="font-size: 16px;font-weight:bold">${params.name}</div>
<div style="font-size: 12px;opacity: 0.9;margin-top: 4px">${data.region || '未知区域'}</div>
</div>
<div style="padding: 12px">
<div style="display: flex;justify-content: space-between;margin: 8px 0">
<span style="color: #666">GDP</span>
<span style="font-weight: bold;color: #667eea">¥${(data.gdp / 10000).toFixed(2)}亿</span>
</div>
<div style="display: flex;justify-content: space-between;margin: 8px 0">
<span style="color: #666">人口</span>
<span style="font-weight: bold">${data.population}万</span>
</div>
<div style="display: flex;justify-content: space-between;margin: 8px 0">
<span style="color: #666">增长率</span>
<span style="font-weight: bold;color: ${data.growth > 0 ? '#91cc75' : '#ee6666'}">
${data.growth > 0 ? '+' : ''}${data.growth}%
</span>
</div>
<div style="margin-top: 12px;padding-top: 8px;border-top: 1px solid #eee">
<div style="font-size: 12px;color: #999">主要产业</div>
<div style="margin-top: 4px">${data.industries.join('、')}</div>
</div>
</div>
</div>
`;
}
};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
37
38
39
40
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
37
38
39
40
🔧 配置详解
完整配置项
javascript
tooltip: {
// 触发
show: true,
trigger: 'item',
triggerOn: 'mousemove', // 'mousemove' | 'click' | 'none'
// 位置
position: null, // 函数或数组
confine: false, // 限制在容器内
// 延迟
showDelay: 0,
hideDelay: 100,
alwaysShowContent: false,
// 样式
backgroundColor: 'rgba(0, 0, 0, 0.7)',
borderColor: '#333',
borderWidth: 0,
padding: 10,
textStyle: {
color: '#fff',
fontSize: 14
},
// 轴指示器
axisPointer: {
type: 'line', // 'line' | 'shadow' | 'cross' | 'none'
lineStyle: {
color: '#999',
width: 1,
type: 'dashed'
},
crossStyle: {
color: '#999'
},
shadowStyle: {
color: 'rgba(0, 0, 0, 0.1)'
}
},
// 额外CSS
extraCssText: 'box-shadow: 0 0 10px rgba(0,0,0,0.2);',
// 值域映射
valueFormatter: function(value) {
return value.toFixed(2);
}
}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
37
38
39
40
41
42
43
44
45
46
47
48
49
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
37
38
39
40
41
42
43
44
45
46
47
48
49
位置控制
javascript
// 方法1: 固定位置
position: [100, 100]
// 方法2: 相对位置
position: ['50%', '50%']
// 方法3: 函数动态计算
position: function(point, params, dom, rect, size) {
// point: 鼠标位置
// params: 数据参数
// dom: tooltip DOM
// rect: 图形边界
// size: {contentSize: [width, height], viewSize: [width, height]}
const x = point[0];
const y = point[1];
const boxWidth = size.contentSize[0];
const boxHeight = size.contentSize[1];
let posX = x + 10;
let posY = y + 10;
// 避免超出边界
if (posX + boxWidth > size.viewSize[0]) {
posX = x - boxWidth - 10;
}
if (posY + boxHeight > size.viewSize[1]) {
posY = y - boxHeight - 10;
}
return [posX, posY];
}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
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
📝 代码示例
示例: 通用富文本提示框生成器
javascript
function createRichTooltip(config = {}) {
const {
title = '{b}',
items = [],
showTotal = false,
theme = 'light'
} = config;
const isDark = theme === 'dark';
const bgColor = isDark ? 'rgba(0, 0, 0, 0.85)' : 'rgba(255, 255, 255, 0.95)';
const textColor = isDark ? '#fff' : '#333';
const borderColor = isDark ? '#444' : '#eee';
return {
trigger: 'axis',
backgroundColor: bgColor,
borderColor: borderColor,
borderWidth: 1,
padding: [12, 16],
textStyle: {
color: textColor,
fontSize: 13
},
formatter: function(params) {
if (!Array.isArray(params) || params.length === 0) return '';
let html = `<div style="padding: 2px">`;
// 标题
html += `<div style="font-size: 14px;font-weight:bold;margin-bottom: 8px;color:${textColor}">`;
html += params[0].name;
html += `</div>`;
// 分割线
html += `<div style="border-top: 1px solid ${borderColor};margin: 8px 0"></div>`;
// 数据项
let total = 0;
params.forEach(param => {
const value = typeof param.value === 'number' ? param.value : param.value[1];
total += value;
html += `<div style="display:flex;align-items:center;margin: 6px 0">`;
html += `<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background-color:${param.color};margin-right:8px"></span>`;
html += `<span style="flex:1;color:${textColor}">${param.seriesName}</span>`;
html += `<span style="font-weight:bold;color:${param.color};margin-left:12px">`;
html += typeof value === 'number' ? value.toLocaleString() : value;
html += `</span>`;
html += `</div>`;
});
// 总计
if (showTotal) {
html += `<div style="border-top: 1px solid ${borderColor};margin: 8px 0"></div>`;
html += `<div style="display:flex;justify-content:space-between;font-weight:bold">`;
html += `<span style="color:${textColor}">总计</span>`;
html += `<span style="color:#5470c6">${total.toLocaleString()}</span>`;
html += `</div>`;
}
html += `</div>`;
return html;
}
};
}
// 使用
const option = {
tooltip: createRichTooltip({
showTotal: true,
theme: 'light'
}),
// ... 其他配置
};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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
⚠️ 常见问题
Q1: 提示框被遮挡?
javascript
tooltip: {
confine: true // ✅ 限制在容器内
}
// 或自定义位置
position: function(point, params, dom, rect, size) {
// 确保不超出边界
return [
Math.min(point[0], size.viewSize[0] - size.contentSize[0]),
Math.min(point[1], size.viewSize[1] - size.contentSize[1])
];
}1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
Q2: 如何显示HTML?
javascript
tooltip: {
formatter: function(params) {
return `
<div style="padding: 10px">
<h3 style="margin: 0 0 8px 0">${params.name}</h3>
<p style="margin: 0">数值: ${params.value}</p>
</div>
`;
}
}1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
Q3: 如何隐藏某些系列?
javascript
series: [{
name: '系列1',
tooltip: { show: true } // 显示
}, {
name: '系列2',
tooltip: { show: false } // 隐藏
}]1
2
3
4
5
6
7
2
3
4
5
6
7
🎯 最佳实践
1. 性能优化
javascript
// 大数据时简化提示框
if (data.length > 10000) {
tooltip: {
formatter: '{b}: {c}', // 简单字符串
showDelay: 100, // 延迟显示
hideDelay: 50
}
}1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
2. 移动端适配
javascript
if (isMobile) {
tooltip: {
triggerOn: 'click', // 点击触发
confine: true, // 限制在容器内
textStyle: {
fontSize: 16 // 增大字体
}
}
}1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
3. 无障碍支持
javascript
tooltip: {
formatter: function(params) {
// 提供清晰的文本描述
return `${params.name}: ${params.value} 单位`;
}
}1
2
3
4
5
6
2
3
4
5
6
📊 性能指标
| 复杂度 | 渲染时间 | 建议 |
|---|---|---|
| 简单(字符串) | < 1ms | 无限制 |
| 中等(函数) | 1-5ms | 正常 |
| 复杂(HTML+富文本) | 5-15ms | 避免高频触发 |
| 非常复杂(嵌套HTML) | > 15ms | 简化结构 |
🔗 相关链接
- click/mouseover 事件
- 富文本 (rich text).md)
- 官方 tooltip 文档
最后更新: 2026-04-23
难度等级: ⭐⭐⭐
预计阅读时间: 22 分钟
提示框组件
{
"title": {
"text": "提示框样式",
"left": "center"
},
"tooltip": {
"trigger": "axis",
"backgroundColor": "rgba(50, 50, 50, 0.9)",
"borderColor": "#333",
"borderWidth": 1,
"borderRadius": 4,
"textStyle": {
"color": "#fff",
"fontSize": 13
},
"padding": [
10,
15
],
"axisPointer": {
"type": "cross",
"crossStyle": {
"color": "#999"
},
"lineStyle": {
"color": "#5470c6",
"width": 2
}
},
"extraCssText": "box-shadow: 0 0 10px rgba(0,0,0,0.3)"
},
"xAxis": {
"type": "category",
"data": [
"周一",
"周二",
"周三",
"周四",
"周五"
]
},
"yAxis": {
"type": "value"
},
"series": [
{
"name": "销售额",
"type": "line",
"smooth": true,
"data": [
150,
230,
224,
218,
260
],
"itemStyle": {
"color": "#5470c6"
},
"areaStyle": {
"opacity": 0.3
}
}
]
}最后更新: 2026-04-23
难度等级: ⭐⭐⭐
预计阅读时间: 22 分钟
